CF每日3题(1400-1700)
最近有点忙,CF练习摆了很长时间,打算之后从3题开始,能练则练。
2126E 1400 数学
- 注意前缀gcd,mingcd,mingcd,min单调递减,lcm,maxlcm,maxlcm,max单调递增
- 还需要一些特殊位置判定
void solve(){int n;cin>>n;vector<int>p(n+1),s(n+1);forr(i,1,n)cin>>p[i];forr(i,1,n)cin>>s[i];if(p[n]!=s[1])return cout<<"no"<<endl,void();//整个数组gcd相等//单调性 以及 p[1]=a[1] s[n]=a[n]forr(i,2,n)if(p[i]>p[i-1]||p[1]%p[i])return cout<<"no"<<endl,void();reforr(i,1,n-1)if(s[i]>s[i+1]||s[n]%s[i])return cout<<"no"<<endl,void();if(p[1]%s[1]||s[n]%p[n])return cout<<"no"<<endl,void();//整个数组gcd和单个数据forr(i,1,n-1){if(p[n]!=__gcd(p[i],s[i+1]))return cout<<"no"<<endl,void();}cout<<"yes"<<endl;
}
2121E 找规律 1500
即要确定一个数和l,r两数同一位子相同的数最少
void solve(){string l,r;cin>>l>>r;int n=l.size(),ans=0;int pre=0;//记录前一位的状态//分析例子发现 对每一位 数字相同+2 差一+1forr(i,0,n-1){int ln=l[i]-'0',rn=r[i]-'0';if(ln==rn&&pre==0)ans+=2;//+2 本位和前一位都相等 eg.331 333 ans=4else if((rn-ln+10)%10==1){//差一 本位不得不取ln或rn 后面取数区间就宽了if(pre==0||(rn==0&&ln==9))ans++,pre=1;//+1 //前一位相同eg.340 351:f(340,342)+f(351,342)=2+1+0//9+1=10有进位 eg1.4299 4300:f(4299,4299)+f(4300,4299)=2+1+1+1//eg2.4291 4300:f(4291,429_)+f(4300,429_)=2+1+1+0else break;}else break;//差的>1 本位可以取ln,rn之间的数 下一位可以取1~10规避l和r}cout<<ans<<endl;
}
2113C 前缀和 1700
分析第三个样例知道
- 第一炸炸出空间,后面就能精准炸出金子,所以也只有第一炸会炸毁金子
- 只考虑第一炸最少会毁坏多少金子,使用前缀和在空地上拓展边长2*k-1的正方形枚举计算
const int N=510,M=998244353;
string s[N];
int sm[N][N];
void solve(){int n,m,k;cin>>n>>m>>k;forr(i,1,n)cin>>s[i],s[i]=' '+s[i];memset(sm,0,sizeof sm);forr(i,1,n){forr(j,1,m){sm[i][j]=sm[i-1][j]+sm[i][j-1]-sm[i-1][j-1]+(s[i][j]=='g');//计算i*j内金块数}}int ans=sm[n][m];//计算第一次爆炸最少能炸多少金块forr(i,1,n){forr(j,1,m){if(s[i][j]=='.'){int tp=sm[min(i+k-1,n)][min(j+k-1,m)]-sm[max(i-k,0ll)][min(j+k-1,m)]-sm[min(i+k-1,n)][max(j-k,0ll)]+sm[max(i-k,0ll)][max(j-k,0ll)];ans=min(tp,ans);}}}cout<<sm[n][m]-ans<<endl;
}