Codeforces Round #369 (Div. 2)
Problem A Bus to Udayland
题目大意
公交车上有些位置能做,有些不能坐,问是否有两个相邻的位置。
解题分析
找到并列的两个O就行。
参考程序
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <string> 8 #include <vector> 9 #include <cstdio> 10 #include <cstdlib> 11 #include <cstring> 12 #include <cassert> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker,"/STACK:102400000,102400000") 16 using namespace std; 17 18 #define N 508 19 #define M 50008 20 #define LL long long 21 #define lson l,m,rt<<1 22 #define rson m+1,r,rt<<1|1 23 #define clr(x,v) memset(x,v,sizeof(x)); 24 #define bitcnt(x) __builtin_popcount(x) 25 #define rep(x,y,z) for (int x=y;x<=z;x++) 26 #define repd(x,y,z) for (int x=y;x>=z;x--) 27 const int mo = 1000000007; 28 const int inf = 0x3f3f3f3f; 29 const int INF = 2000000000; 30 /**************************************************************************/ 31 int n; 32 char s[1008][10]; 33 int main(){ 34 scanf("%d",&n); 35 rep(i,1,n) scanf("%s",s[i]); 36 int flag=0; 37 rep(i,1,n){ 38 if (s[i][0]=='O' && s[i][1]=='O'){ 39 s[i][0]=s[i][1]='+'; 40 flag=1; 41 break; 42 } 43 44 if (s[i][3]=='O' && s[i][4]=='O'){ 45 s[i][3]=s[i][4]='+'; 46 flag=1; 47 break; 48 } 49 } 50 if (flag){ 51 printf("YES\n"); 52 rep(i,1,n) puts(s[i]); 53 } 54 else printf("NO\n"); 55 }
Problem B Chris and Magic Square
题目大意
一个n*n(n<=500)的矩形中有一个格子为空,问是否能填上某个数,使得每行每列以及主对角线之后均相等。
解题分析
n=1特判。n>=2找出某个可能合法的解,填入后再验证一下。 记得开long long。
参考程序
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <string> 8 #include <vector> 9 #include <cstdio> 10 #include <cstdlib> 11 #include <cstring> 12 #include <cassert> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker,"/STACK:102400000,102400000") 16 using namespace std; 17 18 #define N 508 19 #define M 50008 20 #define LL long long 21 #define lson l,m,rt<<1 22 #define rson m+1,r,rt<<1|1 23 #define clr(x,v) memset(x,v,sizeof(x)); 24 #define bitcnt(x) __builtin_popcount(x) 25 #define rep(x,y,z) for (int x=y;x<=z;x++) 26 #define repd(x,y,z) for (int x=y;x>=z;x--) 27 const int mo = 1000000007; 28 const int inf = 0x3f3f3f3f; 29 const int INF = 2000000000; 30 /**************************************************************************/ 31 32 int n,x,y; 33 LL a[1008][1008]; 34 LL work(){ 35 LL sum=0; 36 rep(i,1,n) if (i!=x) 37 { 38 rep(j,1,n) sum+=a[i][j]; 39 break; 40 } 41 LL op=0; 42 LL cnt=0; 43 rep(j,1,n) cnt+=a[x][j]; 44 op=sum-cnt; 45 a[x][y]=op; 46 if (op<=0) return -1; 47 rep(i,1,n) 48 { 49 cnt=0; 50 rep(j,1,n) cnt+=a[i][j]; 51 if (cnt!=sum) return -1; 52 } 53 rep(j,1,n) 54 { 55 cnt=0; 56 rep(i,1,n) cnt+=a[i][j]; 57 if (cnt!=sum) return -1; 58 } 59 cnt=0; 60 rep(i,1,n) cnt+=a[i][i]; 61 if (cnt!=sum) return -1; 62 63 cnt=0; 64 rep(i,1,n) cnt+=a[i][n-i+1]; 65 if (cnt!=sum) return -1; 66 67 return op; 68 69 70 } 71 int main(){ 72 scanf("%d",&n); 73 rep(i,1,n) rep(j,1,n) 74 { 75 scanf("%d",&a[i][j]); 76 if (a[i][j]==0) { x=i; y=j; } 77 } 78 if (n==1) 79 { 80 printf("1\n"); 81 return 0; 82 } 83 printf("%I64d\n",work()); 84 }
Problem C Coloring Trees
题目大意
有n棵树排成一列,一共有m种颜料,有些树被涂了颜色,有些树没有。
可以花费a[i][j]的代价给第i棵树涂上j的颜色。
问给每棵树涂上颜色后,将树恰好分成k段的最小花费。(连续颜色相同的最长区间为一段)
n,m,k<=100
解题分析
只想了个n^4的DP。。还有n^3的做法。
dp[i][j][k]表示做到第i棵树,分成了j段,第i-1棵树的颜色为k。
之后枚举第i棵树的颜色转移即可。
参考程序
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <string> 8 #include <vector> 9 #include <cstdio> 10 #include <cstdlib> 11 #include <cstring> 12 #include <cassert> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker,"/STACK:102400000,102400000") 16 using namespace std; 17 18 #define N 508 19 #define M 50008 20 #define LL long long 21 #define lson l,m,rt<<1 22 #define rson m+1,r,rt<<1|1 23 #define clr(x,v) memset(x,v,sizeof(x)); 24 #define bitcnt(x) __builtin_popcount(x) 25 #define rep(x,y,z) for (int x=y;x<=z;x++) 26 #define repd(x,y,z) for (int x=y;x>=z;x--) 27 const int mo = 1000000007; 28 const int inf = 0x3f3f3f3f; 29 const LL INF = 2000000000000000ll; 30 /**************************************************************************/ 31 32 int n,m,len; 33 LL dp[108][108][108]; 34 LL cost[108][108]; 35 int c[108]; 36 37 void up(LL &x,LL y){ 38 x = min(x,y); 39 } 40 int main(){ 41 rep(i,0,100) rep(j,0,100) rep(k,0,100) dp[i][j][k]=INF; 42 scanf("%d%d%d",&n,&m,&len); 43 rep(i,1,n) scanf("%d",&c[i]); 44 rep(i,1,n) rep(j,1,m) scanf("%I64d",&cost[i][j]); 45 dp[0][1][0]=0; 46 rep(i,0,n-1) rep(j,1,len) rep(k,0,m) 47 { 48 if (dp[i][j][k]!=INF) 49 { 50 if (c[i+1]==0) 51 { 52 rep(col,1,m) if (col!=k) 53 { 54 if (k!=0) up(dp[i+1][j+1][col],dp[i][j][k]+cost[i+1][col]); 55 if (k==0) up(dp[i+1][j][col],dp[i][j][k]+cost[i+1][col]); 56 } 57 if (k!=0) up(dp[i+1][j][k],dp[i][j][k]+cost[i+1][k]); 58 } 59 else 60 { 61 if (c[i+1]==k || k==0) 62 { 63 up(dp[i+1][j][c[i+1]],dp[i][j][k]); 64 } 65 if (c[i+1]!=k && k!=0) 66 { 67 up(dp[i+1][j+1][c[i+1]],dp[i][j][k]); 68 } 69 } 70 } 71 } 72 /* rep(i,0,n) rep(j,1,len) rep(k,0,m) 73 if (dp[i][j][k]!=INF) 74 printf("%d %d %d %I64d\n",i,j,k,dp[i][j][k] );*/ 75 LL ans=INF; 76 rep(k,1,m) up(ans,dp[n][len][k]); 77 printf("%I64d\n",ans==INF ?-1 :ans); 78 }
Problem D Directed Roads
题目大意
有n个点,给定一个数组a[i](≠i),表示有一条i-->a[i]的有向边。
可以将某些有向边的方向翻转,因此共有2^n的方案。
问这些方案中有多少种方案使得所形成的图不含有环。
n<=2*10^5
解题分析
由于一共只有n条边,整个图相当于被分成了若干个联通块,且每个联通块内有且只有一个环。
若某个连通块中有i个点,存在一个点数为j的环,那么其对答案的贡献为2^(i-j) * (2^j-2)
参考程序
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <string> 8 #include <vector> 9 #include <cstdio> 10 #include <cstdlib> 11 #include <cstring> 12 #include <cassert> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker,"/STACK:102400000,102400000") 16 using namespace std; 17 18 #define N 200008 19 #define M 400008 20 #define LL long long 21 #define lson l,m,rt<<1 22 #define rson m+1,r,rt<<1|1 23 #define clr(x,v) memset(x,v,sizeof(x)); 24 #define bitcnt(x) __builtin_popcount(x) 25 #define rep(x,y,z) for (int x=y;x<=z;x++) 26 #define repd(x,y,z) for (int x=y;x>=z;x--) 27 const int mo = 1000000007; 28 const int inf = 0x3f3f3f3f; 29 const int INF = 2000000000; 30 /**************************************************************************/ 31 32 int n,num,huan; 33 int a[N],mi[N+5],vis[N],len[N]; 34 struct line{ 35 int u,v,nt; 36 }eg[M]; 37 int lt[N],sum; 38 39 void add(int u,int v){ 40 eg[++sum]=(line){u,v,lt[u]}; 41 lt[u]=sum; 42 } 43 44 void dfs(int u,int fa) 45 { 46 vis[u]=1; len[u]=len[fa]+1; num++; 47 for (int i=lt[u];i;i=eg[i].nt) 48 { 49 int v=eg[i].v; 50 if (vis[v]==0) 51 { 52 dfs(v,u); 53 } 54 else 55 { 56 if (v!=fa) 57 { 58 huan=abs(len[u]-len[v])+1; 59 } 60 } 61 } 62 } 63 64 int main(){ 65 mi[0]=1; 66 rep(i,1,N) mi[i]=1ll*mi[i-1]*2 % mo; 67 scanf("%d",&n); 68 rep(i,1,n) 69 { 70 scanf("%d",&a[i]); 71 add(i,a[i]); 72 add(a[i],i); 73 } 74 clr(vis,0); 75 LL ans=1; 76 rep(i,1,n) if (vis[i]==0) 77 { 78 num=0; huan=0; 79 dfs(i,0); 80 if (num==2) huan=2; 81 ans = (ans * (mi[huan]-2) % mo * mi[num-huan] % mo); 82 } 83 printf("%I64d\n",ans); 84 85 }
Problem E ZS and The Birthday Paradox
题目大意
假设一年有2^n天,问k个小朋友中有两个小朋友生日相同的概率。
假设该概率约分后为 p / q ,输出p , q对1000003取模的解。
n , k <= 10^18。
解题分析
若k > 2^n 则答案为1 / 1 , 否则答案为 1 - A(2^n,k) / (2^n)^k ,
可以发现分子与分母的gcd必定为2^i。
计算A(2^n,k)=(2^n) * (2^n-1) * ... * (2^n-k+1)含多少个因子2,相当于计算0~k-1以及2^n。
求出gcd后,就可以暴力计算分子,分母对p取模后的结果,再乘上gcd的逆元。
参考程序
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <string> 8 #include <vector> 9 #include <cstdio> 10 #include <cstdlib> 11 #include <cstring> 12 #include <cassert> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker,"/STACK:102400000,102400000") 16 using namespace std; 17 18 #define N 508 19 #define M 50008 20 #define LL long long 21 #define lson l,m,rt<<1 22 #define rson m+1,r,rt<<1|1 23 #define clr(x,v) memset(x,v,sizeof(x)); 24 #define bitcnt(x) __builtin_popcount(x) 25 #define rep(x,y,z) for (int x=y;x<=z;x++) 26 #define repd(x,y,z) for (int x=y;x>=z;x--) 27 const int mo = 1000003; 28 const int inf = 0x3f3f3f3f; 29 const int INF = 2000000000; 30 /**************************************************************************/ 31 LL n,k,num; 32 LL quick(LL x,LL y) 33 { 34 LL res=1; 35 while (y) 36 { 37 if (y & 1) res = res*x % mo; 38 x=x*x % mo; 39 y>>=1; 40 } 41 return res; 42 } 43 int main(){ 44 scanf("%I64d%I64d",&n,&k); 45 if (n<=60 && k>(1ll<<n)){ 46 printf("1 1\n"); 47 return 0; 48 } 49 for (LL kk=k-1;kk;kk/=2) num+=kk/2; 50 LL tmp=quick(2,n),ans=1; 51 rep(i,1,k-1){ 52 ans = ans * (--tmp) % mo; 53 if (tmp==0) break; 54 } 55 ans=ans*quick(quick(2,mo-2),num) % mo; 56 LL ans1=quick(quick(2,n),k-1); 57 ans1=ans1*quick(quick(2,mo-2),num) % mo; 58 ans=ans1-ans; 59 if (ans<0) ans+=mo; 60 printf("%I64d %I64d\n",ans,ans1); 61 62 }