Codeforces Round #533 (Div. 2)
由于长度很小,所以直接暴力枚举最后的长度即可,取最小值即可。
#include<bits/stdc++.h> #define CLR(a,b) memset(a,b,sizeof(a)); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=10010; int a[1100],n; int cost,ans; int main(){ cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; } int co=inf,ans=0; for(int i=1;i<=100;i++) { int tep=0; for(int j=1;j<=n;j++) { if(a[j]>=i+1)tep+=a[j]-1-i; else if(a[j]<=i-1)tep+=i-1-a[j]; } if(tep<co){ co=tep,ans=i; } } cout<<ans<<" "<<co<<endl; }
用数组模拟栈,水题,要读清题意。
#include<bits/stdc++.h> #define CLR(a,b) memset(a,b,sizeof(a)); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=20010; int n; int a[200],ans[200]; int main(){ string s; int k; cin>>n>>k; cin>>s; for(int i=0;i<n;i++) { if(a[s[i]]==0){ CLR(a,0); } a[s[i]]++; ans[s[i]]+=a[s[i]]/k; a[s[i]]%=k; } int maxx=0; for(int i='a';i<='z';i++) { maxx=max(maxx,ans[i]); } cout<<maxx<<endl; }
先预处理出 [ l , r ] ,所有除以3余0,余1,余2的个数,然后dp[ s ][ i ]表示到第 i 位,和的余数为 s 的方案个数,dp式子也很好列,看代码就行了。
#include<bits/stdc++.h> #define CLR(a,b) memset(a,b,sizeof(a)); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=200010; ll p=1e9+7; ll dp[3][maxn],l,r; int n; ll a[3]; int main(){ cin>>n>>l>>r; while(l<=r&&(r-l+1)%3!=0){ a[l%3]++; l++; } a[0]+=(r-l+1)/3; a[1]+=(r-l+1)/3; a[2]+=(r-l+1)/3; dp[0][0]=1; for(int i=1;i<=n;i++) { dp[0][i]=((dp[0][i-1]*a[0]%p)+(dp[1][i-1]*a[2]%p)+(dp[2][i-1]*a[1]%p))%p; dp[1][i]=((dp[0][i-1]*a[1]%p)+(dp[1][i-1]*a[0]%p)+(dp[2][i-1]*a[2]%p))%p; dp[2][i]=((dp[0][i-1]*a[2]%p)+(dp[1][i-1]*a[1]%p)+(dp[2][i-1]*a[0]%p))%p; } printf("%lld\n",dp[0][n]); }
这个题意看的我自闭,看别人的题解才知道自己读错题了,还好打的不是现场的,不然又要掉分了。
题目的意思是有p种人,对于每个人,他可以走到距离 s 范围内的所有格子,而且是可以分身的,走过的地方全部被这个人污染(造起堡垒),然后问各种人污染了几个格子。
如果只有一种人的话,这个bfs只需要处理那些已经走过的区域的最外围就可以了,因为里面那些被包围的肯定没有外围的走的远,最外围的方块就是那些用光了步数才走到的格子,所以这里需要一个bfs。
现在有很多人,并且要依次执行,所以每种人都要用一个队列bord来保存最外围的格子,然后对一种人进行bfs的时候,把这个队列里的所有元素全部倒入主要的bfs队列q,然后对q进行bfs,把步数用光的那些格子塞回bord。
#include<bits/stdc++.h> #define CLR(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1010; int n,m,p; int vis[maxn][maxn]; int ans[20],s[20]; char mp[maxn][maxn]; int fx[4][2]={{0,1},{0,-1},{1,0},{-1,0}}; struct node{ int x,y,step; }; queue<node >q; queue<node >bord[10]; bool check(int x,int y){ if(x<1||x>n||y<1||y>m)return false; if(mp[x][y]=='#')return false; if(vis[x][y]>0)return false; return true; } void bfs(int id) { node st,ne; while(!q.empty()){ st=q.front(); q.pop(); if(st.step==0){ bord[id].push({st.x,st.y,s[id]}); continue; } for(int i=0;i<4;i++) { ne=st; ne.step--; ne.x+=fx[i][0],ne.y+=fx[i][1]; if(check(ne.x,ne.y)){ vis[ne.x][ne.y]=id; q.push(ne); } } } } int expend(int id){ while(!q.empty())q.pop(); while(!bord[id].empty()){ q.push(bord[id].front()); bord[id].pop(); } bfs(id); return !bord[id].empty(); } int main(){ cin>>n>>m>>p; for(int i=1;i<=p;i++)scanf("%d",&s[i]); for(int i=1;i<=n;i++) { scanf("%s",mp[i]+1); } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { int id=mp[i][j]-'0'; if(id>0&&id<=9) { bord[id].push({i,j,s[id]}); vis[i][j]=id; } } } int isok=1; while(isok) { isok=0; for(int i=1;i<=p;i++) { isok|=expend(i); } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { ans[vis[i][j]]++; } } for(int i=1;i<=p;i++) { printf("%d%c",ans[i],i<p?' ':'\n'); } }
可以发现一个性质,就是一个1后面连着的所有人名,必定不能同时开心,也就是这些人直接存在一些反边,对于这40个人来说,我们如果枚举240次,然后把这种反边的关系处理掉,就可以得到答案了。
我们发现,其实这是一个最大独立集的题目,理论上用这种枚举的方式可以过,但是显然时间复杂度太高了,于是我们把人折半,对两部分分别处理,这样的时间复杂度就降为了220*k,k是处理边的常数,虽然有点大,但是有非常多的情况是不会迭代的,所以能过。
对于一个独立子集要怎么做呢,就是要先预处理出所有边的信息,我们先把所有路设为1,然后把那些断掉的路设为0,用状压dp的写法来搞。
两个独立子集思想也是这样,具体看代码,简单易懂.jpg
#include<bits/stdc++.h> #define CLR(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1e5+10; map<string,int>id; bool mp[50][50],vis[maxn]; int cnt,f[1<<21],g[1<<21]; int n,m,op,s1,s2; int sta[maxn],top; string s; void init(){ cnt=0; CLR(f,0),CLR(g,0); CLR(mp,1); } void buildGraph(){ while(n--) { scanf("%d",&op); if(op==1){ for(int i=1;i<top;i++) { for(int j=i+1;j<=top;j++) { mp[sta[i]][sta[j]]=mp[sta[j]][sta[i]]=0; } } top=0; CLR(vis,0); }else{ cin>>s; if(!id.count(s))id[s]=cnt++; if(!vis[id[s]]){ vis[id[s]]=1; sta[++top]=id[s]; } } } for(int i=1;i<top;i++) { for(int j=i+1;j<=top;j++) { mp[sta[i]][sta[j]]=mp[sta[j]][sta[i]]=0; } } top=0; CLR(vis,0); } int main(){ while(cin>>n>>m) { init(); buildGraph(); s1=m/2,s2=m-s1; for(int i=0;i<s1;i++)f[1<<i]=1; for(int i=0;i<s2;i++)g[1<<i]=1; for(int i=0;i<(1<<s1);i++) { for(int j=0;j<s1;j++) { if(i&(1<<j))continue; int flag=1; for(int k=0;k<s1;k++) { if(i&(1<<k)){ flag&=mp[j][k]; } } f[i|(1<<j)]=max(f[i|(1<<j)],f[i]+flag); } } for(int i=0;i<(1<<s2);i++) { for(int j=0;j<s2;j++) { if(i&(1<<j))continue; int flag=1; for(int k=0;k<s2;k++) { if(i&(1<<k)){ flag&=mp[j+s1][k+s1]; } } g[i|(1<<j)]=max(g[i|(1<<j)],g[i]+flag); } } int ans=0; for(int i=0;i<(1<<s1);i++) { int s3=(1<<s2)-1; for(int j=0;j<s1;j++) { if(!(i&(1<<j)))continue; for(int k=0;k<s2;k++) { if(!(s3&(1<<k)))continue; if(mp[j][k+s1]==0){ s3^=(1<<k); } } } ans=max(ans,f[i]+g[s3]); } printf("%d\n",ans); } }