[考试反思]1005csp-s模拟测试60:招魂

最近总是好一场烂一场的。没有连续两场排名波动小于20的。。。

没人管。反正大脸一点脸没有就又AK了。

但是T3爆零这种事情吧。。。

爆搜不是很难打,但是想优化想了半天剩的时间不够结果赶忙打出来了,然后就挂了。

合理安排时间,要把码暴力的时间也考虑到,要检查。

T1T2仍然挂上了对拍,所以没有全盘爆炸。

总体来说是相对简单的一套题。

 

T1:嘟嘟噜

我的思路不太一样。但是复杂度是相似的。

$O(m+log_{\frac{m}{m-1}}\frac{n}{m})$

因为题面里说开无限栈了,然后我就想到了递归打法。

int winner(int n)函数处理剩下n个人时最终胜者的目前编号。

那么如果剩余人数n>m,那么你就可以把n/m个人同时干掉,从第n/m*m+1个人开始数来计算胜者

如果n<=m的话,那就干掉一个人然后继续递归,和约瑟夫一样。

这样的话每次递归,人数会在$-1$和$\times \frac{m-1}{m}$里选一个来 让它快速减小,可以得到上面的复杂度。

据$o0O$打表证明,使n为1e9,当m取到大约1e6时函数的增长速度达到峰值,再之后的增长速度大约为线性。

而本题数据范围1e5时的函数值仅仅是1e5多一点。

总之O(可过)。

 1 #include<cstdio>
 2 int m,n,t;
 3 int winner(int n){
 4     if(n==1)return n;
 5     if(n<m)return (winner(n-1)+m-1)%n+1;
 6     int N=n/m,w=winner(n-N);
 7     if(N*m+w<=n)return N*m+w;
 8     w-=n-N*m;return (w-1)/(m-1)*m+(w-1)%(m-1)+1;
 9 }
10 main(){
11     scanf("%d",&t);
12     while(t--)scanf("%d%d",&n,&m),printf("%d\n",winner(n));
13 }
View Code

 

T2:天才绅士少女助手克里斯蒂娜

这道题是放假前让zkq出数据的那道题(这数据不是现成的嘛,还白给他送了个AC)

化式子,拆平方,最后发现要求的就是$\sum\limits_{i=l}^r \sum\limits_{j=l}^r x_i^2 y_j^2 - x_i y_i x_j y_j$

乘法分配律,得到的就是区间$(\sum\limits_{i=l}^{r}x_i^2)\times(\sum\limits_{i=l}^{r}y_i^2) - (\sum\limits_{i=l}^{r}x_iy_i)^2$

线段树或树状数组维护区间$x^2,y^2,xy$的和即可。注意常数。

 1 #include<cstdio>
 2 #define mod 20170927
 3 int cl[4000005],cr[4000005],x2[4000005],y2[4000005],xy[4000005],x[1000005],y[1000005],XY,X2,Y2;
 4 int read(){
 5     register int p=0;register char ch=getchar();
 6     while(ch<'0'||ch>'9')ch=getchar();
 7     while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-48,ch=getchar();
 8     return p;
 9 }
10 #define lc p<<1
11 #define rc p<<1|1
12 int Mod(int p){return p>=mod?p-mod:p;}
13 void up(int p){x2[p]=Mod(x2[lc]+x2[rc]);y2[p]=Mod(y2[lc]+y2[rc]);xy[p]=Mod(xy[lc]+xy[rc]);}
14 void build(int p,int l,int r){
15     cl[p]=l;cr[p]=r;
16     if(l==r){long long x=read(),y=read();x2[p]=x*x%mod;y2[p]=y*y%mod;xy[p]=x*y%mod;return;}
17     build(lc,l,l+r>>1);build(rc,(l+r>>1)+1,r);up(p);
18 }
19 void chg(int p,int pos){
20     if(cl[p]==cr[p]){long long x=read(),y=read();x2[p]=x*x%mod;y2[p]=y*y%mod;xy[p]=x*y%mod;return;}
21     chg(cr[lc]>=pos?lc:rc,pos);up(p);
22 }
23 void ask(int p,int l,int r){
24     if(l<=cl[p]&&cr[p]<=r){XY=Mod(XY+xy[p]);X2=Mod(X2+x2[p]);Y2=Mod(Y2+y2[p]);return;}
25     if(l<=cr[lc])ask(lc,l,r);if(r>=cl[rc])ask(rc,l,r);
26 }
27 main(){
28     int n=read(),m=read(),opt,p;
29     build(1,1,n);
30     while(m--){opt=read();p=read();
31         if(opt==1)chg(1,p);
32         else XY=X2=Y2=0,ask(1,p,read()),printf("%d\n",Mod((1ll*X2*Y2-1ll*XY*XY)%mod+mod));
33     }
34 }
View Code

 

T3:凤凰院凶真

没想到。《算法竞赛进阶指南》上的原题竟然也不会做了。

想的是三维,表示a串到了i位,b串到了j位,匹配的最大值是k的最大值。

然而最后一维可以压掉,可以发现最后一维与前两维有关。

我们只要强制b串的第j位必选就行了,这样就能得知最后一个选的是几,即最大值是几。

简单的n3枚举。

 1 #include<cstdio>
 2 int n,m,x[5005],y[5005],fr[5001][5001],sta[5005],top;
 3 short dp[5001][5001];
 4 void upd(int i,int j,int li,int lj,int w){
 5     if(dp[i][j]>dp[li][lj]+1)return;
 6     dp[i][j]=dp[li][lj]+w;
 7     fr[i][j]=lj;
 8 }
 9 void get_back(int i,int j){if(i==0||j==0)return;
10     int lj=fr[i][j];
11     if(j!=lj)sta[++top]=y[j];
12     get_back(i-1,lj);
13 }
14 int main(){
15     scanf("%d",&n);
16     for(int i=1;i<=n;++i)scanf("%d",&x[i]);
17     scanf("%d",&m);
18     for(int i=1;i<=m;++i)scanf("%d",&y[i]);
19     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)
20         if(x[i]==y[j]){for(int k=0;k<j;++k)if(y[k]<x[i])upd(i,j,i-1,k,1);}
21         else upd(i,j,i-1,j,0);
22     int M=0;for(int i=1;i<=m;++i)if(dp[n][i]>dp[n][M])M=i;
23     printf("%d\n",dp[n][M]);
24     get_back(n,M);
25     for(int i=top;i;--i)printf("%d ",sta[i]);puts("");
26 }
View Code

优化,边扫边记录上一层的最优决策。n2

 1 #include<cstdio>
 2 int n,m,x[5005],y[5005],fr[5001][5001],sta[5005],top;
 3 short dp[5001][5001];
 4 void upd(int i,int j,int li,int lj,int w){
 5     if(dp[i][j]>dp[li][lj]+1)return;
 6     dp[i][j]=dp[li][lj]+w;
 7     fr[i][j]=lj;
 8 }
 9 void get_back(int i,int j){if(i==0||j==0)return;
10     int lj=fr[i][j];
11     if(j!=lj)sta[++top]=y[j];
12     get_back(i-1,lj);
13 }
14 int main(){
15     scanf("%d",&n);
16     for(int i=1;i<=n;++i)scanf("%d",&x[i]);
17     scanf("%d",&m);
18     for(int i=1;i<=m;++i)scanf("%d",&y[i]);
19     for(int i=1;i<=n;++i){
20         int bst=0,bp=0;
21         for(int j=1;j<=m;++j){
22             if(x[i]==y[j])upd(i,j,i-1,bp,1);
23             else upd(i,j,i-1,j,0);
24             if(y[j]<x[i]&&dp[i-1][j]>bst)bst=dp[i-1][j],bp=j;
25         }
26     }
27     int M=0;for(int i=1;i<=m;++i)if(dp[n][i]>dp[n][M])M=i;
28     printf("%d\n",dp[n][M]);
29     get_back(n,M);
30     for(int i=top;i;--i)printf("%d ",sta[i]);puts("");
31 }
View Code

回溯统计答案没什么好说的。

思路积累:

  • 当dp维数过多导致复杂度高时,要考虑每维之间是否有联系,能否用一维表示另外一维。

 

posted @ 2019-10-05 14:15  DeepinC  阅读(273)  评论(4编辑  收藏  举报