Codeforces Round #568题解
第一次遇到有9题的div2。。。
A题
排序后,伸展两边
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=2e5+10; const int mod=1e9+7; ll a[4]; int main(){ ios::sync_with_stdio(false); ll d; cin>>a[1]>>a[2]>>a[3]>>d; sort(a+1,a+4); ll ans=0; ans+=max(0ll,d-a[2]+a[1]); ans+=max(0ll,d-a[3]+a[2]); cout<<ans<<endl; return 0; }
B题
写了个臭暴力,因为输入的是按序的,所以一位一位匹配,当不同了,看看B有没有机会变成和当前的一样的,其实就是越过中间相等的部分
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=2e5+10; const int mod=1e9+7; int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ string a,b; cin>>a>>b; int i,j; int flag=0; for(i=0,j=0;i<a.size()&&j<b.size();){ if(a[i]==b[j]){ i++,j++; } else{ int tmp=j; while(j<b.size()&&b[j]==b[j-1]){ j++; } if(tmp==j){ flag=1; break; } } } if(flag){ cout<<"NO"<<endl; } else{ if(i!=a.size()){ flag=1; } j--; for(i=j+1;i<b.size();i++){ if(b[i]!=b[j]){ flag=1; break; } } if(flag){ cout<<"NO"<<endl; } else{ cout<<"YES"<<endl; } } } return 0; }
C题
分为两个version,直接讲hard,这题就是当前数必取,之后能在M范围内前面的数取的越多越好
不难想到使用优先队列,但是过了这个数后,这个数不一定要取,因此维护一个对顶堆,先让当前满足条件,然后把数加回来
有个很重要的点是,权值不大于100,因此每次操作不大于100次
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=2e5+10; const int mod=1e9+7; int a[N]; ll sum[N]; int ans[N]; priority_queue<int> q; priority_queue<int,vector<int>,greater<int>> p; int main(){ ios::sync_with_stdio(false); int n,m; cin>>n>>m; int i; for(i=1;i<=n;i++){ cin>>a[i]; sum[i]=sum[i-1]+a[i]; } ll tot=0; for(i=1;i<=n;i++){ p.push(a[i]); while(tot+a[i]>m){ int tmp=q.top(); q.pop(); p.push(tmp); tot-=tmp; } ans[i]=i-q.size()-1; while(p.size()){ int tmp=p.top(); if(tot+tmp<=m){ tot+=tmp; p.pop(); q.push(tmp); } else{ break; } } int tmp=a[i]; } for(i=1;i<=n;i++){ cout<<ans[i]<<" "; } cout<<endl; return 0; }
D题
先排序
维护一个map,因为权值相等,就是相当于要不只有一个树,要不只有一种差值,因此我们枚举哪个差值要删除,然后看有没有合适情况
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=2e5+10; const int mod=1e9+7; int a[N]; int b[N]; map<ll,int> m1; map<ll,int> pos; int main(){ ios::sync_with_stdio(false); int n; cin>>n; int i; for(i=1;i<=n;i++){ cin>>a[i]; pos[a[i]]=i; } sort(a+1,a+1+n); for(i=2;i<=n;i++){ b[i]=a[i]-a[i-1]; } for(i=2;i<=n;i++){ m1[b[i]]++; } int flag=0; for(i=1;i<=n;i++){ if(i==1){ int tmp=a[2]-a[1]; m1[tmp]--; if(m1[tmp]==0){ m1.erase(tmp); } if(m1.size()==0||m1.size()==1){ flag=1; cout<<pos[a[1]]<<endl; break; } m1[tmp]++; } else if(i==n){ int tmp=a[n]-a[n-1]; m1[tmp]--; if(m1[tmp]==0){ m1.erase(tmp); } if(m1.size()==0||m1.size()==1){ flag=1; cout<<pos[a[n]]<<endl; break; } m1[tmp]++; } else{ int f1=a[i]-a[i-1]; int f2=a[i+1]-a[i]; int f3=a[i+1]-a[i-1]; m1[f1]--; m1[f2]--; m1[f3]++; if(m1[f1]==0){ m1.erase(f1); } if(m1[f2]==0){ m1.erase(f2); } if(m1.size()==0||m1.size()==1){ flag=1; cout<<pos[a[i]]<<endl; break; } m1[f1]++; m1[f2]++; m1[f3]--; if(m1[f3]==0){ m1.erase(f3); } } } if(!flag){ cout<<-1<<endl; } return 0; }
E题
暴力题
首先把每个字母所有的位置存下来,然后从小到大枚举,如果没有,那就取最后一个字母的随便一个位置,因为这个位置一定是不被覆盖了
如果一个,那就这个位置,如果有多个,那就枚举这个字母的位置看是否符合情况
最后check一遍看是否和原来一样
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=5e5+10; const int mod=1e9+7; struct node{ int x,y; }; struct Node{ int a,b,c,d; }; vector<node> pos[2020]; vector<Node> ans; int a[2020][2020]; int b[2020][2020]; int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ ans.clear(); int n,m; cin>>n>>m; int i,j,k; for(i=0;i<=26;i++){ pos[i].clear(); } for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ a[i][j]=0; b[i][j]=0; } } int mx=0; for(i=1;i<=n;i++){ string s; cin>>s; s=" "+s; for(j=1;j<=m;j++){ if(s[j]=='.') continue; a[i][j]=s[j]-'a'+1; pos[a[i][j]].push_back({i,j}); mx=max(mx,a[i][j]); } } int flag=0; for(i=1;i<=mx;i++){ if(pos[i].size()==0){ int x=pos[mx][0].x,y=pos[mx][0].y; ans.push_back({x,y,x,y}); } else if(pos[i].size()==1){ int x=pos[i][0].x,y=pos[i][0].y; ans.push_back({x,y,x,y}); } else{ int x1=pos[i][0].x,y1=pos[i][0].y; int x2=pos[i][1].x,y2=pos[i][1].y; if(x1!=x2&&y1!=y2){ flag=1; break; } if(x1==x2){ for(auto x:pos[i]){ if(x.x!=x1){ flag=1; break; } } } if(y1==y2){ for(auto x:pos[i]){ if(x.y!=y1){ flag=1; break; } } } ans.push_back({x1,y1,pos[i][pos[i].size()-1].x,pos[i][pos[i].size()-1].y}); } } if(flag){ cout<<"NO"<<endl; continue; } for(i=0;i<mx;i++){ for(j=ans[i].a;j<=ans[i].c;j++){ for(k=ans[i].b;k<=ans[i].d;k++){ b[j][k]=i+1; } } } for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ if(a[i][j]!=b[i][j]){ flag=1; break; } } if(flag) break; } if(flag){ cout<<"NO"<<endl; } else{ cout<<"YES"<<endl; cout<<mx<<endl; for(i=0;i<mx;i++){ cout<<ans[i].a<<" "<<ans[i].b<<" "<<ans[i].c<<" "<<ans[i].d<<endl; } } } return 0; }
F题
一道状压,感觉比较好想,因为时限给了4s。
我们看到有9种,不难想到可以状压出状态,首先n和m的关系不能直接算,因为数据太大
因此需要一个媒介联通他们,这样这个不大于1024的数就起到了作用,我们发现如果可以枚举1024种情况,再分别维护n,m,复杂度在1e8左右
因此想到,1024种情况,分别计算他能够符合多少人,然后我们枚举面包,因为只能取两个面包,所以需要维护选这个面包能到达的状态的花费最小值和id
这样我们就可以枚举1024种情况计算选两个面包的答案
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=1e6+10; const int mod=1e9+7; ll f[N]; ll d[N]; ll cost[N],st[N],id[N]; vector<int> res; int main(){ ios::sync_with_stdio(false); int n,m; int i,j,k; cin>>n>>m; for(i=1;i<=n;i++){ int x; cin>>x; for(j=1;j<=x;j++){ int tmp; cin>>tmp; f[i]|=(1<<(tmp-1)); } } int ans=0; int tot=0x3f3f3f3f; memset(cost,0x3f,sizeof cost); for(i=0;i<1<<10;i++){ for(j=1;j<=n;j++){ if((f[j]&i)==f[j]){ d[i]++; } } } res.push_back(1); res.push_back(2); for(i=1;i<=m;i++){ ll x,c; cin>>x>>c; int tmp=0; for(j=1;j<=c;j++){ int y; cin>>y; tmp|=(1<<(y-1)); } for(j=0;j<1<<10;j++){ if(st[j]){ if(ans<d[j|tmp]){ ans=d[j|tmp]; tot=cost[j]+x; res.clear(); res.push_back(id[j]); res.push_back(i); } else if(ans==d[j|tmp]&&tot>cost[j]+x){ tot=cost[j]+x; res.clear(); res.push_back(id[j]); res.push_back(i); } } } st[tmp]=1; if(cost[tmp]>x){ cost[tmp]=x; id[tmp]=i; } } cout<<res[0]<<" "<<res[1]<<endl; return 0; }
G1题
状压dp,根据题目范围,设计状态为选择i,最后的种类是j,这样往大了更新即可
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=2e5+10; const int mod=1e9+7; int a[N],b[N]; ll f[N][4]; int main(){ ios::sync_with_stdio(false); int n,T; cin>>n>>T; int i,j,k; for(i=1;i<=n;i++){ cin>>a[i]>>b[i]; } f[0][0]=1; for(i=0;i<(1<<n);i++){ for(j=0;j<=3;j++){ for(k=1;k<=n;k++){ if(i>>(k-1)&1) continue; if(b[k]==j) continue; f[i|(1<<k-1)][b[k]]=(f[i|(1<<k-1)][b[k]]+f[i][j])%mod; } } } ll ans=0; for(i=1;i<(1<<n);i++){ int cnt=0; for(j=1;j<=n;j++){ if(i>>(j-1)&1){ cnt+=a[j]; } } if(cnt==T){ ans=(ans+f[i][1]+f[i][2]+f[i][3])%mod; } } cout<<ans<<endl; return 0; }
G2题
待补,没啥思路。
没有人不辛苦,只有人不喊疼