[考试反思]0921csp-s模拟测试49:困顿
太弱。还是太弱。
拉不开分差,离第一机房分数线估计还是300多分。
但是,还是要骂:XX出题人。
部分分非常少且没有意义,T1基本只有0/纯暴力20/100三个档,
T2正解是n2但是n3一分不给,还要卡n2的空间,T3的n5有51分但没有任何提示,除了送了与正解根本就无关的7分。
而且造的数据还出了锅,这个出题人啊。。。
出题人是有多痛恨人类。
开考看题。
T1上来先看错了题以为是xor,然后就是trie裸题了,然后直接开始打。
很快地打出来发现过不了样例,然后发现是mod。
重新看题,全不会,傻眼了。
想再找一道最简单的题先做稳住,但是无从下手。
刚开始T2有一个n3的思路,发现没有设分,就绝望了。
想了一个半小时多吧,想出了n2,然后发现卡空间。
太弱了没有直接想到正解,zkt就知道直接按x排序,我和脸和toot都是按y排的。
然后大脸秒掉了空间优化,toot放弃了空间优化拿80分走了。
我以为只有50分于是不想放弃,但是剩下两题还没有打,于是走了。
回去弄了一个T1的随机化+测试点分治暴力,然后忘记取模,本来40分的代码炸成0了。
因为没有打正解所以就没有打对拍。。。
然后T3顺手把特殊性质7分拿下,直接放弃。
回T2,对拍,然后空间优化。
思路还可以,可以节约25%的空间,但是忘了vector会翻倍导致空间浪费,于是结果就是和toot没优化一样,80分。
暴力也要打对拍。
对于卡空间的题要精打细算,注意vector的2倍空间。
get黑科技:resize。
还是没有能把所有能拿下的分拿下,还是弱啊。。。
T1:养花
分块。预处理块中对于100001的所有询问的最大答案。
预处理的方法类似于lower_bound但是可以记在数组上就去掉了不必要的log。
开数组lst[i]记录下这个块里小于等于i的值里的最大值。
那么对于每一个询问就可以搞了:mod k的最大值就是max(lst[k-1],lst[2k-1]-k,lst[3k-1]-2k...)
而计算这个式子的复杂度是调和级数$\sum\limits_{i=1}^{n} \frac{n}{i} = ln n$
所以总的复杂度就是$O(\sqrt{n} \times 100001 \times ln 100001 + m \sqrt{n})$
然而其实不是$\sqrt{n}$,会T的,块要开的稍大一点(1300左右)跑的能快一些
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 #define S 1234 5 #define N 100001 6 int lst[100005],n,m,x[130005],Ans[101][130005],bl[130005]; 7 int main(){ 8 scanf("%d%d",&n,&m); 9 const int bs=(n-1)/S+1; 10 for(int i=1;i<=n;++i)scanf("%d",&x[i]); 11 for(int i=1;i<=bs;++i){ 12 for(int j=1;j<=N;++j)lst[j]=0; 13 for(int j=(i-1)*S+1;j<=i*S&&j<=n;++j)lst[x[j]]=x[j],bl[j]=i; 14 for(int j=1;j<=N;++j)lst[j]=max(lst[j-1],lst[j]); 15 for(int j=2;j<=N;++j)for(int k=j;;k+=j){ 16 if(k>N){Ans[i][j]=max(Ans[i][j],lst[N]%j);break;} 17 Ans[i][j]=max(Ans[i][j],lst[k-1]%j); 18 } 19 } 20 for(int t=1,l,r,q;t<=m;++t){ 21 scanf("%d%d%d",&l,&r,&q);int ans=0; 22 if(bl[l]==bl[r])for(int i=l;i<=r;++i)ans=max(ans,x[i]%q); 23 else{ 24 for(int i=l;i<=bl[l]*S;++i)ans=max(ans,x[i]%q); 25 for(int i=(bl[r]-1)*S+1;i<=r;++i)ans=max(ans,x[i]%q); 26 for(int i=bl[l]+1;i<bl[r];++i)ans=max(ans,Ans[i][q]); 27 }printf("%d\n",ans); 28 } 29 }
思路积累:
- 分块不一定都是暴力。
- 预处理所有询问。
T2:折射
dp式子都不一样。我说我的按y排序后的n2空间的了。(因为另一种我并想不到)
先把x离散化,然后按y排序。我是dp[i][j]表示选到了第i个装置,上上个选的装置的x是j。
先考虑n3,emm还是不说了吧真的是暴力啊,加个if就行。
然后其实我们发现是一个区间加,那么前缀和一下复杂度就对了。
这时候的dp[i][x[j]]+=dp[j][x[i]];
我们发现对于每一个i只从前面的i-1项转移而来,那么总的就是1/2 n2而不是n2
那么我们把要加的项目提前放进vector里,把dp数组滚动,就不会再炸空间了。
1 #include<cstdio> 2 #include<algorithm> 3 #include<vector> 4 using namespace std; 5 vector<int>num[6001]; 6 vector<short>pos[6001]; 7 int mod(int p){return p>=1000000007?p-1000000007:p;} 8 struct ps{int x,y;friend bool operator<(ps a,ps b){return a.y>b.y;}}p[6005]; 9 bool com(ps a,ps b){return a.x<b.x;} 10 int dp[6001],n,ans; 11 int main(){ 12 scanf("%d",&n); 13 for(int i=1;i<=n;++i)scanf("%d%d",&p[i].x,&p[i].y); 14 sort(p+1,p+1+n,com); 15 for(int i=1;i<=n;++i)p[i].x=i; 16 sort(p+1,p+1+n); 17 for(int i=1;i<=n;++i) num[i].resize(i-1),pos[i].resize(i-1); 18 for(int i=1;i<=n;++i){ 19 for(int j=1;j<=n;++j)dp[j]=0; 20 for(int j=0;j<num[i].size();++j)dp[pos[i][j]]=mod(dp[pos[i][j]]+num[i][j]); 21 num[i].clear();pos[i].clear(); 22 for(int j=1;j<i;++j)dp[p[j].x]++; 23 for(int j=1;j<p[i].x;++j)dp[j]=mod(dp[j]+dp[j-1]); 24 for(int j=n;j>p[i].x;--j)dp[j]=mod(dp[j]+dp[j+1]); 25 ans=mod(ans+mod(dp[p[i].x-1]+dp[p[i].x+1])); 26 for(int j=i+1;j<=n;++j)num[j][j-i-1]=dp[p[j].x],pos[j][j-i-1]=p[i].x; 27 } 28 printf("%d\n",mod(ans+n)); 29 }
思路积累:
- resize
- 前缀和
T3:画作
大神题。
有一个结论就是最优方案中一定有一种的所有操作的交集不是空集。
那么我们只要抓住某一个点向四周扩展,把所有同色区域取反就好了,知道全部区域都是白色。
复杂度$O(n^5)$
同色区域被多次扩展了,我们只在乎最远的点几次能扩展几次。
同色连0边,异色连1边,跑bfs即可。
因为懒得打双端队列所以开了100个队列。。。(因为曼哈顿距离不会超过100)
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 const int xx[]={1,0,0,-1},yy[]={0,1,-1,0}; 5 #define tx X+xx[p] 6 #define ty Y+yy[p] 7 char s[55][55];int o[55][55],n,m,dt[55][55],qx[105][2555],qy[105][2555],qh[105],qt[105],ans=123; 8 int main(){ 9 scanf("%d%d",&n,&m); 10 for(int i=1;i<=n;++i)scanf("%s",s[i]+1); 11 for(int x=1;x<=n;++x)for(int y=1;y<=m;++y)dt[x][y]=1000; 12 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)o[i][j]=s[i][j]-'0'; 13 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){ 14 dt[i][j]=0;qh[0]=qt[0]=1;qx[0][1]=i;qy[0][1]=j; 15 for(int k=1;k<=100;++k)qh[k]=1,qt[k]=0; 16 for(int k=0;k<=100;++k)for(int l=qh[k];l<=qt[k];++l){ 17 int X=qx[k][l],Y=qy[k][l]; 18 for(int p=0;p<=3;++p)if(dt[tx][ty]>dt[X][Y]+(o[X][Y]^o[tx][ty])) 19 dt[tx][ty]=dt[X][Y]+(o[X][Y]^o[tx][ty]), 20 qx[dt[tx][ty]][++qt[dt[tx][ty]]]=tx, 21 qy[dt[tx][ty]][qt[dt[tx][ty]]]=ty; 22 } 23 int mx=0; 24 for(int x=1;x<=n;++x)for(int y=1;y<=m;++y)mx=max(mx,dt[x][y]),dt[x][y]=1000; 25 mx+=mx&1^o[i][j]; 26 ans=min(ans,mx); 27 }printf("%d\n",ans); 28 }