\(n\)天没更博了,由于被膜你赛的毒瘤题虐哭了。。。html
既然打了此次CF仍是记念一下。ios
看看NOIP以前,接下来几场的时间都很差。这应该是最后一场CF了,差\(4\)分上紫也是一个遗憾吧。c++
给一个矩形,每次从外面剥掉一圈,按剥去次序的奇偶分开,问最前\(k\)个奇数圈的总面积。数组
普及组题,直接模拟。spa
#include<bits/stdc++.h> #define LL long long #define RG register #define R RG int using namespace std; int main(){ LL w,h,k,ans=0; cin>>w>>h>>k; while(k--){ ans+=2*(w+h-2); w-=4;h-=4; } cout<<ans<<endl; return 0; }
给两个长度为\(n\)的序列\(\{a\},\{b\}\),构造一个长度为\(n\)的序列\(\{t\}\)使得\(t_i|t_{i+1}=a_i,t_i\&t_{i+1}=b_i\)。code
一看到题就想着乱搞,找到一个合法的就直接构造。htm
不想DFS了,由于感受若是直接构造WA了的话DFS不是也会TLE么?blog
而后就过了。。。ci
#include<bits/stdc++.h> #define LL long long #define RG register #define R RG int using namespace std; const int N=100009; int n,a[N],b[N],t[N]; bool check(){ for(R i=0;i<n-1;++i){ for(t[i+1]=0;t[i+1]<4;++t[i+1]) if((t[i]|t[i+1])==a[i]&&(t[i]&t[i+1])==b[i])break; if(t[i+1]==4)return 0; } return 1; } int main(){ ios::sync_with_stdio(0); cin>>n; for(R i=0;i<n-1;++i)cin>>a[i]; for(R i=0;i<n-1;++i)cin>>b[i]; for(t[0]=0;t[0]<4;++t[0]) if(check()){ puts("YES"); for(R i=0;i<n;++i)printf("%d ",t[i]); return puts(""),0; } puts("NO"); return 0; }
给定正整数\(a,b\),找到最大的正整数\(s\),要求全部\(1-s\)的数能被分红两组,第一组的和\(\le a\),第二组的和\(\le b\)。get
又是乱搞。。。
首先\(s\)有个上限,\(\frac{s(s+1)}2\le a+b\)。而后\(s\)取到上限的时候必定能够构造?
而后把数从大往小丢进\(a\)里,能丢就丢。剩下的就给\(b\)了。
而后由于\(s\)的极限值估计错了数组开小RE一发。而后就过了。若是这里少罚点时应该也能上紫了。
#include<bits/stdc++.h> #define LL long long #define RG register #define R RG int using namespace std; bool f[70000]; int main(){ RG LL a,b,s,p=0; cin>>a>>b; s=(sqrt(8*(a+b)+1)-1)/2.0; for(R i=s;i;--i) if(a>=i)a-=i,f[i]=1,++p; cout<<p<<endl; for(R i=1;i<=s;++i)if( f[i])printf("%d ",i);puts(""); cout<<s-p<<endl; for(R i=1;i<=s;++i)if(!f[i])printf("%d ",i);puts(""); return 0; }
给一个\(n*n\)的字母方阵,能够把\(k\)个字母改为a,求字典序最小的从\((1,1)\)到\((n,n)\)的路径。
首先,把路径最前面不是a的换成a显然更优。那么若是\((1,1)\)到某个位置的路径上最多有不超过\(k\)个字母不为a,这个位置能够并且必须改为a。\(O(n^2)\)暴力处理一下就行了。
接着直接开始找。字典序最小怎么办?一开始我这个菜鸡脑壳短路了,问了下神仙\(\text{yyb}\),“不就是按副对角线转移么?”,瞬间懂了。。。
找字典序最小确定要在相同长度的状况下贪心。而以同一条副对角线结尾的路径长度固然相同啦!每次字典序最小的都是一个集合,直接用这个集合的全部后继找到下一长度的字典序最小的集合。
调了半天,只是由于最小后继初始化的时候放错了位置。。。后面就没时间杠E了。若是这里少罚点时应该也能上紫了。
#include<bits/stdc++.h> #define LL long long #define RG register #define R RG int using namespace std; const int N=2009; char s[N][N],ans[N]; int f[N][N],X[2][N],Y[2][N]; bool pr[N][N],vis[N][N]; inline void chkmn(R&x,R y){if(x>y)x=y;} int main(){ R n,k; RG char mn; cin>>n>>k; for(R i=1;i<=n;++i)cin>>(s[i]+1); for(R i=1;i<=n;++i) for(R j=1;j<=n;++j){ f[i][j]=(i==1&&j==1?0:3*N); if(i!=1)chkmn(f[i][j],f[i-1][j]); if(j!=1)chkmn(f[i][j],f[i][j-1]); f[i][j]+=s[i][j]!='a'; if(f[i][j]<=k)s[i][j]='a'; } R*x1=X[0],*x2=X[1],*y1=Y[0],*y2=Y[1],p1=1,p2=0,x,y; x1[1]=y1[1]=1; for(R i=1;i<=2*n;++i){ mn=127; for(;p1;--p1){ x=x1[p1];y=y1[p1]; if(x<n&&!vis[x+1][y]&&mn>=s[x+1][y]){ if(mn>s[x+1][y])mn=s[x+1][y],p2=1; else ++p2; vis[x2[p2]=x+1][y2[p2]=y]=1; } if(y<n&&!vis[x][y+1]&&mn>=s[x][y+1]){ if(mn>s[x][y+1])mn=s[x][y+1],p2=1; else ++p2; vis[x2[p2]=x][y2[p2]=y+1]=pr[x][y+1]=1; } } swap(x1,x2);swap(y1,y2);swap(p1,p2); } for(x=n,y=n;x!=1||y!=1;pr[x][y]?--y:--x) ans[x+y-2]=s[x][y]; ans[0]=s[1][1]; puts(ans); return 0; }
给一个\(01\)序列,每次能够翻转\(x,y,z\)三个位置的数位(假设\(x<y<z\),那么需知足\(y-x=z-y\) ),构造总次数不超过\(\lfloor\frac n 3\rfloor+12\)的操做序列使原序列全变成\(0\)。
赛场上觉得要想fstqwq的星空那题同样异或差分还差分什么的。而后就结束了。
晚上发现了一个有用的思路:从后往前作,第\(i\)位碰到\(1\)就作一次\((i-2,i-1,i)\)的操做,最后只会剩下前\(3\)位,这时候若是还不能直接消掉,就是剩下一个或者两个\(1\),而剩两个\(1\)又能够直接转化成剩一个\(1\)。
手动模拟,假如只有第一位一个\(1\),能够经过\((1,4,7)(3,5,7)(3,4,5)\)把它消掉。这个\(1\)在第二位、第三位也是同样。那也就是说,若是序列长度大于等于\(9\),则必定有解:小于\(9\)有没有解?直接状压暴搜都够了。
如今问题在于怎样减小操做次数。既然是\(\frac n 3\),咱们天然会想,可不能够只用一次操做就使最后\(3\)位都归零呢?有一个特例\(011\),尝试失败了。接着,咱们只好尝试可不能够只用两次操做使最后\(6\)位归零。通过手动模拟(状态\(2^6\),慎用)、打表暴枚以后,咱们能够证实尝试成功了。
而后就用打出来的表一个个归零啊,等到序列长度小于\(12\)的时候,直接开状压BFS暴搜。
#include<bits/stdc++.h> #define LL long long #define RG register #define R RG int using namespace std; const int N=1e5+9,M=99,Q=2099; int a[N],ax[N],c[M],d[M],id1[M],id2[M],q[Q],dis[Q],pr[Q]; int main(){ R n,p=0,ans=0,x,y; cin>>n; for(R i=1;i<=n;++i)cin>>a[i]; for(R i=0;i<6;++i) for(R j=1;i-2*j>=-6;++j){ c[++p]=i;d[p]=j; x=1<<i;x|=(x>>j)|(x>>2*j); if(!id1[x])id1[x]=p; } for(R i=1;i<=p;++i) for(R j=1;j<=p;++j){ x=1<<c[i];x|=(x>>d[i])|(x>>2*d[i]); y=1<<c[j];y|=(y>>d[j])|(y>>2*d[j]); if(!id1[x^=y])id1[x]=i,id2[x]=j; } id1[0]=id2[0]=0; for(R i=n-5;i>6;i-=6){ x=0;for(R j=i+5;j>=i;--j)(x<<=1)|=a[j]; ax[i]=x; if(id1[x]){ R j=i+c[id1[x]],nd=d[id1[x]]; a[j-2*nd]^=1;a[j-nd]^=1;a[j]^=1;++ans; } if(id2[x]){ R j=i+c[id2[x]],nd=d[id2[x]]; a[j-2*nd]^=1;a[j-nd]^=1;a[j]^=1;++ans; } } R S=1<<(p=min(n,11)); memset(dis,-1,4*S); x=0;for(R j=p;j;--j)(x<<=1)|=a[j]; dis[q[0]=x]=0; for(R h=0,t=0;h<=t;++h){ R x=q[h];if(!x)break; for(R i=2;i<p;++i) for(R j=i>>1;j;--j){ y=x^(1<<(i-2*j))^(1<<(i-j))^(1<<i); if(!~dis[y])dis[q[++t]=y]=dis[pr[y]=x]+1; } } if(!~dis[0])return puts("NO"),0; printf("YES\n%d\n",ans+dis[0]); for(x=0;pr[x];x=pr[x]){ R t=0; for(y=x^pr[x];~y&1;y>>=1,++t);printf("%d ",++t); for(y>>=1 ;~y&1;y>>=1,++t);printf("%d ",++t); for(y>>=1 ;~y&1;y>>=1,++t);printf("%d\n",++t); } for(R i=n-5;i>6;i-=6){ x=ax[i]; if(id1[x]){ R j=i+c[id1[x]],nd=d[id1[x]]; printf("%d %d %d\n",j-2*nd,j-nd,j); } if(id2[x]){ R j=i+c[id2[x]],nd=d[id2[x]]; printf("%d %d %d\n",j-2*nd,j-nd,j); } } return 0; }
给两个整数\(a,b\),每次操做能够对一个数乘上一个质数、或除以它的一个质因数,求使两数约数个数相等的最少操做次数。
显然跟惟一分解有关,把数分解成\(\prod p_i^{k_i}\)之后,全部的\(k_i\)就能够压进状态。而后就搜?DP?最短路?
更麻烦的是状态的上界很差控制。而后这题就咕咕了吧。。。
当计算几何练手题作了,题解戳这儿