Codeforces Round #533 (Div. 2)
C:
题意:
有n个整数ai,数列a有两个神奇的性质。1.所有的整数都在[l,r]范围内。2.这n个数的和能被3整除。现在给出l和r,和个数n,问你有多少种方法构造出数列a,方案数mod1e9+7.
题解:
一个数被3除只有三种可能。1.整除,2.余1,2.余2.
然后我们再想这个问题,[l,r]区间内,能被3整除的数有多少?a0=r/3-l/3。余1/2的数有多少?a1/2=((r-l+1)-a0)/2.(这里具体余1和余2不重要,想想为什么)
我们设f[i][j]为前i个数,和除3余j的方案数。怎么转移呢。
f[i][0]=f[i-1][1]*a2+f[i-1][2]*a1+f[i-1][0]*a0.
f[i][1]=f[i-1][0]*a1+f[i-1][1]*a0+f[i-1][2]*a2.
f[i][2]=f[i-1][0]*a2+f[i-1][1]*a1+f[i-1][2]*a0.
1 #include<stdio.h> 2 #include<iostream> 3 using namespace std; 4 5 long long dp[200005][3]; 6 const long long mod=1000000007; 7 int main(){ 8 int n,l,r; 9 cin>>n>>l>>r; 10 long long a0,a1,a2; 11 long long sum=r-l+1; 12 a0=r/3-(l-1)/3; 13 sum-=a0; 14 a1=sum/2; 15 a2=sum-a1 ; 16 dp[1][0]=a0; 17 dp[1][1]=a1; 18 dp[1][2]=a2; 19 for(int i=2;i<=n;i++) 20 { 21 dp[i][0]=(dp[i-1][1]*a2+dp[i-1][0]*a0+dp[i-1][2]*a1)%mod; 22 dp[i][1]=(dp[i-1][1]*a0+dp[i-1][0]*a1+dp[i-1][2]*a2)%mod; 23 dp[i][2]=(dp[i-1][1]*a1+dp[i-1][0]*a2+dp[i-1][2]*a0)%mod; 24 } 25 printf("%I64d\n",dp[n][0]); 26 27 }
D.题意
kilani正在和朋友们玩一个游戏,这个游戏在一个n*m的网格上,每个格子要么是空白,要么是已经被占领,每个玩家有一个或者多个城堡。每个玩家轮流进行游戏。对于玩家i,他可以从一个已有的城堡向一个空白的格子扩建一个城堡,如果这个空白的格子和它的曼哈顿距离不超过s[i]。
求游戏结束后每个玩家占领的格子数量。
题解:
一个多源bfs。具体可以看代码
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <queue> 6 7 #define pir pair<int,int> 8 #define mkp make_pair 9 using namespace std; 10 const int maxn=1000+10; 11 const int dx[]={0,0,1,-1}; 12 const int dy[]={1,-1,0,0}; 13 14 int n,m,p; 15 int a[10],ans[10]; 16 char G[maxn][maxn]; 17 int vis[maxn][maxn]; 18 struct Node{ 19 int x,y,p; 20 }; 21 int main(){ 22 scanf("%d%d%d",&n,&m,&p); 23 for(int i=1;i<=p;i++){ 24 scanf("%d",&a[i]); 25 } 26 queue<pir>q; 27 for(int i=1;i<=n;i++){ 28 for(int j=1;j<=m;j++){ 29 scanf(" %c",&G[i][j]); 30 } 31 } 32 for(int k=1;k<=p;k++){ 33 for(int i=1;i<=n;i++){ 34 for(int j=1;j<=m;j++){ 35 // scanf(" %c",&G[i][j]); 36 if(G[i][j]!='.'&&G[i][j]!='#'&&G[i][j]-'0'==k){ 37 vis[i][j]=k; 38 q.push(mkp(i,j)); 39 } 40 } 41 } 42 } 43 44 45 while(!q.empty()){ 46 pir u=q.front();q.pop(); 47 int x=u.first,y=u.second; 48 int num=vis[x][y]; 49 queue<Node>q2; 50 q2.push({x,y,a[num]}); 51 while(!q.empty()){ 52 pir u1=q.front(); 53 if(vis[u1.first][u1.second]==num){ 54 q.pop(); 55 q2.push({u1.first,u1.second,a[num]}); 56 }else{ 57 break; 58 } 59 } 60 61 while(!q2.empty()){ 62 Node u1=q2.front();q2.pop(); 63 if(u1.p<=0)continue; 64 for(int k=0;k<4;k++){ 65 int nx=u1.x+dx[k]; 66 int ny=u1.y+dy[k]; 67 if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&G[nx][ny]=='.'&&vis[nx][ny]==0){ 68 vis[nx][ny]=num; 69 q2.push({nx,ny,u1.p-1}); 70 q.push(mkp(nx,ny)); 71 } 72 } 73 } 74 75 } 76 77 for(int i=1;i<=n;i++){ 78 for(int j=1;j<=m;j++){ 79 if(vis[i][j]){ 80 ans[vis[i][j]]++; 81 //printf("%d ",vis[i][j]); 82 } 83 } 84 //printf("\n"); 85 } 86 87 for(int i=1;i<=p;i++){ 88 printf("%d ",ans[i]); 89 } 90 return 0; 91 }
E. Helping Hiasat
题意:
Hiasat有一个社交账号,当他的朋友们每次来看他社交首页的时候,如果他首页的名字是这个朋友的名字,他朋友就会很开心。给出一个序列代表可以修改名字的时间和朋友们来访问的顺序,问如何修改才能让开心的朋友们最多。
题解:
显然在两次修改之间的所有访问,只能满足一次。那么其实很显然,将这些点之间连边,然后求图的最大独立集。然后最大独立集怎么求?求补图中的最大团。最大团怎么求?套板子啊!!
1 include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 55; 4 bool mp[maxn][maxn]; 5 int num[maxn], group[maxn], now[maxn]; 6 int n, m, ans; 7 bool dfs(int u, int cnt) 8 { 9 int i, j; 10 for(i = u+1; i <= n; ++i) 11 { 12 if(num[i]+cnt <= ans) return false; //��֦3 13 if(mp[u][i]) 14 { 15 for(j = 0; j < cnt; ++j) 16 if(!mp[i][now[j]]) break; 17 if(j == cnt) //�Ż� 18 { 19 now[cnt] = i; 20 if(dfs(i, cnt+1)) return true; 21 } 22 } 23 } 24 if(cnt > ans) 25 { 26 for(i = 0; i < cnt; ++i) 27 group[i] = now[i]; 28 ans = cnt; 29 return true; 30 } 31 return false; 32 } 33 34 int MaximumClique() 35 { 36 ans = -1; 37 for(int i = n; i >= 1; --i) 38 { 39 now[0] = i; 40 dfs(i, 1); 41 num[i] = ans; 42 } 43 return ans; 44 } 45 map<string,int>Name; 46 int name_num; 47 int N,M; 48 int G[maxn][maxn]; 49 50 int main() 51 { 52 scanf("%d%d",&N,&M); 53 vector<int>per; 54 set<int>S; 55 for(int i=1;i<=N;i++){ 56 int type; 57 scanf("%d",&type); 58 if(type==1){ 59 per.clear(); 60 S.clear(); 61 }else{ 62 string name; 63 cin>>name; 64 if(!Name.count(name)){ 65 Name[name]=++name_num; 66 } 67 if(!S.count(Name[name])){ 68 S.insert(Name[name]); 69 for(int i=0;i<per.size();i++){ 70 int u=per[i]; 71 G[u][Name[name]]=1; 72 G[Name[name]][u]=1; 73 } 74 per.push_back(Name[name]); 75 } 76 } 77 } 78 n=name_num; 79 for(int i=1;i<=n;i++){ 80 for(int j=1;j<=n;j++){ 81 mp[i][j]=!G[i][j]; 82 } 83 } 84 printf("%d\n",MaximumClique()); 85 // while(cin >> n && n) 86 // { 87 // for(int i = 1; i <= n; ++i) 88 // for(int j = 1; j <= n; ++j) 89 // { 90 // int x; cin >> x; 91 // mp[i][j] = x; 92 // } 93 // cout << MaximumClique() << endl; 94 // } 95 return 0; 96 }