Codeforces Round #199 (Div. 2)
-----------------------------
A. Xenia and Divisors
---
将n个数3个一组分成满足条件的n/3组。
由于数字最多是7,所以只有124、126、136三种分组方式。
先分出所有的136,再分出124,126。若所有数字都用光则分组成功。
---
#include <iostream> using namespace std; int n; int a[10]={0}; bool check(){ for (int i=1;i<=7;i++) if (a[i]<0) return true; return false; } int main() { cin>>n; for (int i=0;i<n;i++){ int t; cin>>t; a[t]++; } if (n%3!=0){ cout<<-1<<endl; return 0; } if (a[5]>0||a[7]>0){ cout<<-1<<endl; return 0; } int c1,c2,c3; c1=a[3]; a[1]-=c1; a[3]-=c1; a[6]-=c1; if (check()){ cout<<-1<<endl; return 0; } c2=a[6]; a[1]-=c2; a[2]-=c2; a[6]-=c2; if (check()){ cout<<-1<<endl; return 0; } c3=a[4]; a[1]-=c3; a[2]-=c3; a[4]-=c3; if (check()){ cout<<-1<<endl; return 0; } if (c1*3+c2*3+c3*3!=n){ cout<<-1<<endl; return 0; } for (int i=1;i<=7;i++) if (a[i]!=0) { cout<<-1<<endl; return 0; } for (int i=0;i<c3;i++) cout<<"1 2 4"<<endl; for (int i=0;i<c2;i++) cout<<"1 2 6"<<endl; for (int i=0;i<c1;i++) cout<<"1 3 6"<<endl; return 0; }-----------------------------
B. Xenia and Spies
---
n个人,s要将纸条传到f。传一次用时1。
有m次观察,对于每次观察,第t秒时区间[l,r]不能传递或接受纸条。
问最少用多少时间才能将纸条传到f。
贪心传递即可,若能传递则尽可能传递。
若m次观察后还没有传到f,则要继续传到f。
---
/** head-file **/ #include <iostream> #include <fstream> #include <sstream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstring> #include <string> #include <vector> #include <queue> #include <stack> #include <list> #include <set> #include <map> #include <algorithm> /** define-for **/ #define REP(i, n) for (int i=0;i<int(n);++i) #define FOR(i, a, b) for (int i=int(a);i<int(b);++i) #define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i) #define REP_1(i, n) for (int i=1;i<=int(n);++i) #define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i) #define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i) #define REP_N(i, n) for (i=0;i<int(n);++i) #define FOR_N(i, a, b) for (i=int(a);i<int(b);++i) #define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i) #define REP_1_N(i, n) for (i=1;i<=int(n);++i) #define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i) #define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i) /** define-useful **/ #define clr(x,a) memset(x,a,sizeof(x)) #define sz(x) int(x.size()) #define see(x) cerr<<#x<<" "<<x<<endl #define se(x) cerr<<" "<<x #define pb push_back #define mp make_pair /** test **/ #define Display(A, n, m) { \ REP(i, n){ \ REP(j, m) cout << A[i][j] << " "; \ cout << endl; \ } \ } #define Display_1(A, n, m) { \ REP_1(i, n){ \ REP_1(j, m) cout << A[i][j] << " "; \ cout << endl; \ } \ } using namespace std; /** typedef **/ typedef long long LL; /** Add - On **/ const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} }; const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} }; const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} }; const int MOD = 1000000007; const int INF = 0x3f3f3f3f; const long long INFF = 1LL << 60; const double EPS = 1e-9; const double OO = 1e15; const double PI = acos(-1.0); //M_PI; int n,m,s,f; struct QAQ{ int t,l,r; }a[211111]; bool check(int x,int l,int r){ if (x>=l&&x<=r) return true; return false; } int u; vector<char>vec; int main() { vec.clear(); cin>>n>>m>>s>>f; u=1; REP(i,m) cin>>a[i].t>>a[i].l>>a[i].r; REP(i,m){ int t,l,r; t=a[i].t; l=a[i].l; r=a[i].r; while (u<t){ if (s<f) vec.push_back('R'),s++; if (s>f) vec.push_back('L'),s--; if (s==f) break; u++; } if (s==f) break; if (check(s,l,r)){ vec.push_back('X'); } else if (s<f&&check(s+1,l,r)){ vec.push_back('X'); } else if (s>f&&check(s-1,l,r)){ vec.push_back('X'); } else{ if (s<f) vec.push_back('R'),s++; if (s>f) vec.push_back('L'),s--; } if (s==f) break; u++; } while (s!=f) { if (s<f) vec.push_back('R'),s++; if (s>f) vec.push_back('L'),s--; } REP(i,sz(vec)){ cout<<vec[i]; } cout<<endl; return 0; }-----------------------------
C. Cupboard and Balloons
---
将半径为r/2的圆球放进柜子里。
首先考虑高为h的矩形区域,可证出两两并排向里放圆球最优。
当放满h/r*2个球后,考虑剩下的空间。
有三种可能,放1个,放2个,放3个。。
---
#include <iostream> #include <cmath> using namespace std; int main() { int r,h; int ans=0; cin>>r>>h; ans+=h/r*2; h=h%r; if (h>=sqrt(3)/2*r) ans+=3; else if (h>=1.0*r/2) ans+=2; else ans+=1; cout<<ans<<endl; return 0; }-----------------------------
---
问3XN的格子有多少种骨牌摆放方案使其变成一个合理的游戏。
若只考虑摆放方案,不考虑游戏是否合理(即空格是否可以移动),则问题转化成了传统的状态压缩dp。
对于空格的x坐标。若x=1或x=3,可以发现无论骨牌怎样摆放,空格都是可以移动的。
对于x=2。
若空格右侧有空间(y+2<=n),则将空格右侧横放一个骨牌,再dp求出此时的方案数。
若左侧有空间,则左侧横放骨牌,求出方案数。
若左右都有空间,则将左右各方骨牌,总方案数减去此时的方案数。
得出答案。
---
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> using namespace std; const int MAXN=16384; const int MOD=1000000007; char s[4][MAXN]; int f[MAXN][8]; int n,sx,sy; void input(){ cin>>n; for (int i=1;i<=3;i++){ cin>>(s[i]+1); } } void findDot(){ for (int i=1;i<=3;i++){ for (int j=1;j<=n;j++){ if (s[i][j]=='O'){ sx=i; sy=j; return; } } } } int getBit(int j){ int res=0; for (int i=1;i<=3;i++){ if (s[i][j]!='.') res|=(1<<(3-i)); } return res; } int getDP(int i,int k){ if (k==0) return f[i-1][7];// 000 <- 111 if (k==1) return f[i-1][6];// 001 <- 110 if (k==2) return f[i-1][5];// 010 <- 101 if (k==3) return (f[i-1][4]+f[i-1][7])%MOD;// 011 <- 100,111 if (k==4) return f[i-1][3];// 100 <- 011 if (k==5) return f[i-1][2];// 101 <- 010 if (k==6) return (f[i-1][1]+f[i-1][7])%MOD;// 110 <- 001,111 if (k==7) return ((f[i-1][0]+f[i-1][3])%MOD+f[i-1][6])%MOD;// 111 <- 000,011,110 return -1; } int solve(){ memset(f,0,sizeof(f)); f[0][7]=1; for (int i=1;i<=n;i++){ int k=getBit(i); for (int j=k;j<=7;j++){ if ((j&k)==k){ f[i][j]=getDP(i,j&(~k)); } } } return f[n][7]; } int special(){ int ans=0; bool lb=false,rb=false; if (sy-2>=1){ if (s[2][sy-1]=='.'&&s[2][sy-2]=='.'){ s[2][sy-1]=s[2][sy-2]='X'; ans+=solve(); s[2][sy-1]=s[2][sy-2]='.'; lb=true; } } if (sy+2<=n){ if (s[2][sy+1]=='.'&&s[2][sy+2]=='.'){ s[2][sy+1]=s[2][sy+2]='X'; ans+=solve(); s[2][sy+1]=s[2][sy+2]='.'; rb=true; } } if (lb&&rb){ s[2][sy-1]=s[2][sy-2]='X'; s[2][sy+1]=s[2][sy+2]='X'; ans-=solve(); s[2][sy-1]=s[2][sy-2]='.'; s[2][sy+1]=s[2][sy+2]='.'; } while (ans<0) ans+=MOD; ans%=MOD; return ans; } int main() { input(); findDot(); if (sx==2) cout<<special()<<endl; else cout<<solve()<<endl; return 0; }-----------------------------
E. Xenia and Tree
---
有一棵n个节点的树,根节点为红色,其它节点没有颜色,给出m个操作。
1 x :将节点x染成红色
2 x :输出节点x的距红色节点的最短距离
平方分割法。令block=sqrt(m)。
对于操作1,将待染色节点其加入队列que
对于操作2,若队列元素个数>block,则利用队列里的红色节点做一次bfs,更新所有点到红色节点的最短距离。并输出dis[x];
若元素个数不足block,则将dis[x]与点x到队列里所有的元素的距离做比较,并输出。
求树上两点间的最短距离,用LCA实现。
---
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> #include <queue> #include <stack> #include <cmath> using namespace std; const int maxn=211111; const int maxm=611111; const int INF=0x3f3f3f; //------最短路---------- struct EdgeNode{ int to; int next; }; EdgeNode edges[maxm]; int head[maxn],edge,n; void addedge(int u,int v){ edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++; } void init(){ memset(head,-1,sizeof(head)); edge=0; } //---------MAIN--------------- bool vis[maxn]; int dis[maxn]; queue<int>que; int block; void dfs(int u,int pa){ if (pa==0) dis[u]=0; else dis[u]=dis[pa]+1; for (int i=head[u];i!=-1;i=edges[i].next){ int v=edges[i].to; if (v!=pa) dfs(v,u); } } void bfs(){ memset(vis,0,sizeof(vis)); while (!que.empty()){ int u=que.front(); que.pop(); for (int i=head[u];i!=-1;i=edges[i].next){ int v=edges[i].to; if (dis[u]+1<dis[v]){ dis[v]=dis[u]+1; if (!vis[v]){ que.push(v); vis[v]=true; } } } } } //-----RMQ-------------- int d[maxn][30]; //元素从1编号到n void makeRmqIndex(int A[],int n){ for(int i=1;i<=n;i++) d[i][0]=i; for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) d[i][j] = A[d[i][j-1]] < A[d[i+(1<<(j-1))][j-1]]? d[i][j-1]:d[i+(1<<(j-1))][j-1]; } int rmqIndex(int L,int R,int A[]){ int k=0; while ((1<<(k+1))<=R-L+1) k++; return A[d[L][k]]<A[d[R-(1<<k)+1][k]]? d[L][k]:d[R-(1<<k)+1][k]; } //------LCA------------------------ int deep[maxn]; int E[maxn*2],R[maxn],D[maxn*2],mn; void dfs(int u,int p,int d){ E[++mn]=u; D[mn]=d; R[u]=mn; for (int i=head[u];i!=-1;i=edges[i].next){ int v=edges[i].to; if (v==p) continue; dfs(v,u,d+1); E[++mn]=u; D[mn]=d; } } void getd(int u,int p,int w){ deep[u]=w; for (int i=head[u];i!=-1;i=edges[i].next){ int v=edges[i].to; if (v==p) continue; getd(v,u,w+1); } } void LCA_init(){ mn=0; memset(R,0,sizeof(R)); dfs(1,-1,1); makeRmqIndex(D,mn); getd(1,-1,0); } int LCA(int u,int v){ if (R[u]>=R[v]) return E[rmqIndex(R[v],R[u],D)]; else return E[rmqIndex(R[u],R[v],D)]; } int getDis(int u,int v){ int lca=LCA(u,v); return deep[u]+deep[v]-deep[lca]*2; } int main() { int m; int x,y; scanf("%d%d",&n,&m); init(); block=sqrt(m); for (int i=1;i<n;i++){ scanf("%d%d",&x,&y); addedge(x,y); addedge(y,x); } dfs(1,0); LCA_init(); for (int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); if (x==1){ que.push(y); dis[y]=0; } else if (x==2){ if ((int)que.size()>block){ bfs(); printf("%d\n",dis[y]); } else{ int ans=dis[y]; int bg=0; while (!que.empty()){ int q=que.front(); if (bg==0) bg=q; else if (bg==q) break; que.pop(); ans=min(ans, getDis(y,q) ); que.push(q); } printf("%d\n",ans); } } } return 0; }
-----------------------------
---
---