A.
题解:枚举答案,验证
代码:
1 #include<bits/stdc++.h> 2 #define maxn 1005 3 using namespace std; 4 int n; 5 int a[maxn]; 6 int main() 7 { 8 scanf("%d",&n); 9 for(int i=1;i<=n;++i)scanf("%d",&a[i]); 10 int ans=1,val=100000000; 11 for(int k=1;k<=100;++k) 12 { 13 int t=0; 14 for(int i=1;i<=n;++i) 15 { 16 if(a[i]>k)t+=a[i]-(k+1); 17 if(a[i]<k)t+=(k-1)-a[i]; 18 } 19 if(t<val)val=t,ans=k; 20 } 21 printf("%d %d ",ans,val); 22 return 0; 23 }
B.
题解:考虑到每个长度为k的串的字母相同,用two-pointers维护出现次数,然后在长度为k字母相同的串结尾位置标记val=1,最后对每种字母DP就行
1 #include<bits/stdc++.h> 2 #define maxn 200005 3 using namespace std; 4 int n,k; 5 char s[maxn]; 6 int val[maxn]; 7 int c[30],num; 8 int dp[maxn]; 9 int main() 10 { 11 scanf("%d%d",&n,&k); 12 scanf("%s",s+1); 13 for(int l=1;l<=k;++l) 14 { 15 int t=s[l]-'a'; 16 if(!c[t])num++; 17 c[t]++; 18 } 19 for(int r=k;r<=n;++r) 20 { 21 if(num==1)val[r]=1; 22 int l=r-k+1; 23 if(c[s[l]-'a']==1)num--; 24 c[s[l]-'a']--; 25 if(r!=n) 26 { 27 if(!c[s[r+1]-'a'])num++; 28 c[s[r+1]-'a']++; 29 } 30 } 31 int ans=0; 32 for(int p=0;p<26;++p) 33 { 34 for(int i=k;i<=n;++i) 35 { 36 dp[i]=dp[i-1]; 37 if(s[i]-'a'==p&&dp[i]<dp[i-k]+val[i])dp[i]=dp[i-k]+val[i]; 38 } 39 ans=max(ans,dp[n]); 40 } 41 printf("%d ",ans); 42 return 0; 43 }
C.
题解:简单计数DP,按 mod 3 分类。
1 #include<bits/stdc++.h> 2 #define maxn 200005 3 #define ll long long 4 using namespace std; 5 const ll mod = 1000000007; 6 int n; 7 ll l,r; 8 ll val[4]; 9 ll dp[maxn][4]; 10 int main() 11 { 12 scanf("%d%I64d%I64d",&n,&l,&r); 13 ll t=(r-l+1)/3,d=(r-l+1)%3; 14 if(d==0)val[0]=val[1]=val[2]=t; 15 if(d==1) 16 { 17 val[0]=val[1]=val[2]=t; 18 int x=(int)(l%3); 19 val[x]++; 20 } 21 if(d==2) 22 { 23 val[0]=val[1]=val[2]=t; 24 int x=(int)(l%3); 25 int y=(int)((l+1)%3); 26 val[x]++;val[y]++; 27 } 28 dp[0][0]=1; 29 for(int i=1;i<=n;++i) 30 { 31 dp[i][0]=(dp[i-1][0]*val[0]%mod+dp[i-1][1]*val[2]%mod+dp[i-1][2]*val[1]%mod)%mod; 32 dp[i][1]=(dp[i-1][0]*val[1]%mod+dp[i-1][1]*val[0]%mod+dp[i-1][2]*val[2]%mod)%mod; 33 dp[i][2]=(dp[i-1][0]*val[2]%mod+dp[i-1][1]*val[1]%mod+dp[i-1][2]*val[0]%mod)%mod; 34 } 35 int ans=dp[n][0]; 36 printf("%d ",ans); 37 return 0; 38 }
D.
题解:开p个队列,每次从可扩展点开始bfs就行
1 #include<bits/stdc++.h> 2 #define maxn 1005 3 using namespace std; 4 int n,m,p; 5 char a[maxn][maxn]; 6 int s[maxn]; 7 struct node 8 { 9 int x,y; 10 node(){} 11 node(int X,int Y){x=X;y=Y;} 12 }; 13 queue<node> q[10]; 14 stack<node> stk; 15 int dis[maxn][maxn]; 16 int Ans[10]; 17 int main() 18 { 19 scanf("%d%d%d",&n,&m,&p); 20 for(int i=1;i<=p;++i)scanf("%d",&s[i]); 21 for(int i=1;i<=n;++i)scanf("%s",a[i]+1); 22 for(int i=1;i<=n;++i) 23 for(int j=1;j<=m;++j) 24 { 25 int k=a[i][j]-'0'; 26 if(1<=k&&k<=p)q[k].push(node(i,j)); 27 } 28 while(1) 29 { 30 for(int k=1;k<=p;++k) 31 { 32 while(!q[k].empty()) 33 { 34 node u=q[k].front(); 35 q[k].pop(); 36 int x=u.x,y=u.y; 37 if(a[x-1][y]=='.'||a[x+1][y]=='.'||a[x][y-1]=='.'||a[x][y+1]=='.') 38 { 39 stk.push(u); 40 dis[x][y]=0; 41 } 42 } 43 while(!stk.empty()) 44 { 45 q[k].push(stk.top()); 46 stk.pop(); 47 } 48 } 49 int flag=0; 50 for(int k=1;k<=p;++k)if(!q[k].empty())flag=1; 51 if(!flag)break; 52 for(int k=1;k<=p;++k) 53 { 54 while(!q[k].empty()) 55 { 56 node u=q[k].front();q[k].pop(); 57 int x=u.x,y=u.y; 58 if(dis[x][y]==s[k]) 59 { 60 stk.push(u); 61 continue; 62 } 63 if(a[x-1][y]=='.') 64 { 65 dis[x-1][y]=dis[x][y]+1; 66 a[x-1][y]='0'+k; 67 q[k].push(node(x-1,y)); 68 } 69 if(a[x+1][y]=='.') 70 { 71 dis[x+1][y]=dis[x][y]+1; 72 a[x+1][y]='0'+k; 73 q[k].push(node(x+1,y)); 74 } 75 if(a[x][y-1]=='.') 76 { 77 dis[x][y-1]=dis[x][y]+1; 78 a[x][y-1]='0'+k; 79 q[k].push(node(x,y-1)); 80 } 81 if(a[x][y+1]=='.') 82 { 83 dis[x][y+1]=dis[x][y]+1; 84 a[x][y+1]='0'+k; 85 q[k].push(node(x,y+1)); 86 } 87 } 88 while(!stk.empty()) 89 { 90 node u=stk.top(); 91 stk.pop(); 92 q[k].push(u); 93 } 94 } 95 } 96 for(int i=1;i<=n;++i) 97 for(int j=1;j<=m;++j) 98 { 99 int k=a[i][j]-'0'; 100 if(1<=k&&k<=p)Ans[k]++; 101 } 102 for(int i=1;i<=p;++i)printf("%d ",Ans[i]); 103 return 0; 104 }
E.
题解:
考虑这个序列,连续的一堆1是没有意义的,我们可以缩成一个;
然后就是1 2 2 2 …… 1 2 2 ……这样的形式;
对于每个1后面缀着的2,我们只能选1个,因此,只要有两个人在某段中共用一个1,那么这两个人就不能同时选;
这是个最大独立集问题,我们考虑转化成补图的最大团;
m=40,求最大团有不少方法,这里使用一个写起来简单的方法:随机化
考虑随机一个排列,然后贪心地选择点加入最大团,做个上千次就很对了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m; 4 map<string,int> mp; 5 bool has[42][100005]; 6 int a[42][42]; 7 int p[42]; 8 bool is[42]; 9 int ans,Ans[42]; 10 int main() 11 { 12 scanf("%d%d",&n,&m); 13 int last=0,cnt=0; 14 for(int i=1;i<=n;++i) 15 { 16 int opt; 17 scanf("%d",&opt); 18 if(opt==1)++last; 19 else 20 { 21 string s; 22 cin>>s; 23 if(!mp.count(s))mp[s]=++cnt; 24 has[mp[s]][last]=1; 25 } 26 } 27 for(int i=1;i<=m;++i) 28 { 29 for(int j=i+1;j<=m;++j) 30 { 31 bool yes=1; 32 for(int k=1;k<=last;++k)if(has[i][k]&&has[j][k])yes=0; 33 if(yes)a[i][j]=a[j][i]=1; 34 } 35 } 36 for(int i=1;i<=m;++i)p[i]=i; 37 srand(time(NULL)); 38 for(int t=1;t<=3000;++t) 39 { 40 random_shuffle(p+1,p+m+1); 41 memset(is,0,sizeof(is)); 42 int num=0; 43 for(int i=1;i<=m;++i) 44 { 45 bool ok=1; 46 for(int j=1;j<i;++j)if(is[p[j]]&&!a[p[i]][p[j]])ok=0; 47 if(ok)is[p[i]]=1,num++; 48 } 49 if(num>ans) 50 { 51 ans=0; 52 for(int i=1;i<=m;++i)if(is[p[i]])Ans[++ans]=p[i]; 53 } 54 } 55 printf("%d ",ans); 56 return 0; 57 }