1001 Traversal
1002 Best Solver
1003 Minimum Cut
类似于POJ 3417的做法。
考虑每条新边对树边的覆盖次数。
每条树边被覆盖的次数其实就是断裂这条树边后还需断裂的新边数。
定义dp[i]为节点i向树根方向的边被新边覆盖次数。离线LCA后树DP。
答案为dp[2]~dp[n]中的最小值+1。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 using namespace std; 6 # define CLR(x) memset(x,0,sizeof(x)) 7 # define INF 1000000 8 const int maxn=20000+10,maxm=200000+10; 9 int tot[2],h[2][maxn],dp[maxn],pa[maxn]; 10 bool vis[maxn]; 11 12 struct node 13 { 14 int to,pre; 15 } edge[2][maxm<<1]; 16 17 void add(int op,int from,int to) 18 { 19 tot[op]++; 20 edge[op][tot[op]].pre=h[op][from]; 21 edge[op][tot[op]].to=to; 22 h[op][from]=tot[op]; 23 } 24 25 int Find(int x) 26 { 27 return pa[x]==x?x:pa[x]=Find(pa[x]); 28 } 29 30 void LCA(int x,int f) 31 { 32 for(int i=h[0][x];i;i=edge[0][i].pre) 33 { 34 int to=edge[0][i].to; 35 if(to==f) continue; 36 LCA(to,x); 37 pa[to]=x; 38 } 39 vis[x]=1; 40 for(int i=h[1][x];i;i=edge[1][i].pre) 41 { 42 int to=edge[1][i].to; 43 if(vis[to]) dp[Find(to)]-=2; 44 } 45 return; 46 } 47 48 void dfs(int pos,int f) 49 { 50 for(int i=h[0][pos];i;i=edge[0][i].pre) 51 { 52 int to=edge[0][i].to; 53 if(to==f) continue; 54 dfs(to,pos); 55 dp[pos]+=dp[to]; 56 } 57 for(int i=h[1][pos];i;i=edge[1][i].pre) 58 { 59 int to=edge[1][i].to; 60 if(!vis[to]) continue; 61 dp[pos]++; dp[to]++; 62 } 63 vis[pos]=0; 64 return; 65 } 66 67 int main(void) 68 { 69 int T; cin>>T; 70 for(int kase=1;kase<=T;kase++) 71 { 72 int n,m; scanf("%d%d",&n,&m); 73 CLR(tot); CLR(h); CLR(vis); CLR(dp); 74 for(int i=0;i<n-1;i++) 75 { 76 int a,b; scanf("%d%d",&a,&b); 77 add(0,a,b); add(0,b,a); 78 } 79 for(int i=n-1;i<m;i++) 80 { 81 int a,b; scanf("%d%d",&a,&b); 82 add(1,a,b); add(1,b,a); 83 } 84 for(int i=1;i<=n;i++) pa[i]=i; 85 LCA(1,0); dfs(1,0); 86 int ans=INF; 87 for(int i=2;i<=n;i++) ans=min(ans,dp[i]); 88 printf("Case #%d: %d ",kase,ans+1); 89 } 90 return 0; 91 }
1005 Excited Database
把每条斜对角线看成一个点。主副两个方向分别建一颗线段树。
线段树的每个节点维护a[i]的和、i*a[i]的和、(2*n-i)*a[i]的和。
每次询问分别计算主副两个方向的增值。
询问的矩形拆成两个三角形和一个平行四边形。
三角形覆盖可以分别用i*a[i]与(2*n-i)*a[i]做差计算。
平行四边形覆盖直接用a[i]乘边长即可。
如图假设要用一颗线段树求虚线框内副对角线方向的贡献。
拆成两个蓝三角和一个灰色平行四边形。
左上的蓝三角用i*a[i]处理。转化成一个大三角减去黄三角再减去两个绿色平行四边形。
右下同理用(2*n-i)*a[i]类似的处理。
中间平行四边形直接用a[i]乘矩形高。
主对角线方向的一样处理。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 typedef long long LL; 7 #define now tree[op][pos] 8 #define ls tree[op][pos*2] 9 #define rs tree[op][pos*2+1] 10 #define maxn 400010 11 int n; 12 13 struct node 14 { 15 int l,r; 16 LL a,ia,na,tag; 17 } tree[2][maxn<<2]; 18 19 void build(int op,int pos,int l,int r) 20 { 21 now.l=l; now.r=r; 22 now.a=now.ia=now.na=0; 23 if(l<r) 24 { 25 build(op,pos*2,l,(l+r)/2); 26 build(op,pos*2+1,(l+r)/2+1,r); 27 } 28 return; 29 } 30 31 void pushdown(int op,int pos) 32 { 33 if(now.tag) 34 { 35 ls.tag+=now.tag; 36 ls.a+=(LL)(ls.r-ls.l+1)*now.tag; 37 ls.ia+=(LL)(ls.l+ls.r)*(LL)(ls.r-ls.l+1)/2*now.tag; 38 ls.na+=(LL)(4*n-ls.l-ls.r)*(LL)(ls.r-ls.l+1)/2*now.tag; 39 rs.tag+=now.tag; 40 rs.a+=(LL)(rs.r-rs.l+1)*now.tag; 41 rs.ia+=(LL)(rs.l+rs.r)*(LL)(rs.r-rs.l+1)/2*now.tag; 42 rs.na+=(LL)(4*n-rs.l-rs.r)*(LL)(rs.r-rs.l+1)/2*now.tag; 43 now.tag=0; 44 } 45 return; 46 } 47 48 void pushup(int op,int pos) 49 { 50 now.a=ls.a+rs.a; 51 now.ia=ls.ia+rs.ia; 52 now.na=ls.na+rs.na; 53 return; 54 } 55 56 void update(int op,int pos,int l,int r) 57 { 58 if(now.l>=l&&now.r<=r) 59 { 60 now.tag++; 61 now.a+=(LL)(now.r-now.l+1); 62 now.ia+=(LL)(now.l+now.r)*(LL)(now.r-now.l+1)/2; 63 now.na+=(LL)(4*n-now.l-now.r)*(LL)(now.r-now.l+1)/2; 64 return; 65 } 66 pushdown(op,pos); 67 if(l<=(now.l+now.r)/2) update(op,2*pos,l,r); 68 if(r>=(now.l+now.r)/2+1) update(op,2*pos+1,l,r); 69 pushup(op,pos); 70 return; 71 } 72 73 LL query(int op,int pos,char c,int l,int r) 74 { 75 if(l<=now.l&&r>=now.r) 76 { 77 if(c=='a') return now.a; 78 if(c=='i') return now.ia; 79 if(c=='n') return now.na; 80 } 81 LL ret=0; 82 pushdown(op,pos); 83 if(l<=(now.l+now.r)/2) ret+=query(op,pos*2,c,l,r); 84 if(r>=(now.l+now.r)/2+1) ret+=query(op,pos*2+1,c,l,r); 85 return ret; 86 } 87 88 int main(void) 89 { 90 int T; cin>>T; 91 for(int kase=1;kase<=T;kase++) 92 { 93 int q; 94 scanf("%d%d",&n,&q); 95 printf("Case #%d: ",kase); 96 build(0,1,1,2*n-1);//-1 97 build(1,1,1,2*n-1);//+n 98 for(int i=0;i<q;i++) 99 { 100 int type;scanf("%d",&type); 101 if(type==1) 102 { 103 int L,R; 104 scanf("%d%d",&L,&R); 105 update(0,1,L-1,R-1); 106 } 107 else if(type==2) 108 { 109 int L,R; 110 scanf("%d%d",&L,&R); 111 update(1,1,L+n,R+n); 112 } 113 else 114 { 115 int x1,y1,x2,y2; 116 scanf("%d%d%d%d",&x1,&x2,&y1,&y2); 117 int w=y2-y1+1,h=x2-x1+1; 118 LL ans=0; 119 if(w>=h) 120 { 121 ans+=query(0,1,'i',x1+y1-1,x2+y1-2); 122 ans-=query(0,1,'a',x1+y1-1,x2+y1-2)*(LL)(x1+y1-2); 123 ans+=query(0,1,'n',x1+y2,x2+y2-1); 124 ans-=query(0,1,'a',x1+y2,x2+y2-1)*(LL)(2*n-x2-y2); 125 ans+=query(0,1,'a',x2+y1-1,x1+y2-1)*(LL)h; 126 ans+=query(1,1,'i',x1-y2+n,x2-y2+n-1); 127 ans-=query(1,1,'a',x1-y2+n,x2-y2+n-1)*(LL)(x1-y2+n-1); 128 ans+=query(1,1,'n',x1-y1+n+1,x2-y1+n); 129 ans-=query(1,1,'a',x1-y1+n+1,x2-y1+n)*(LL)(y1-x2+n-1); 130 ans+=query(1,1,'a',x2-y2+n,x1-y1+n)*(LL)h; 131 } 132 else 133 { 134 ans+=query(0,1,'i',x1+y1-1,x1+y2-2); 135 ans-=query(0,1,'a',x1+y1-1,x1+y2-2)*(LL)(x1+y1-2); 136 ans+=query(0,1,'n',x2+y1,x2+y2-1); 137 ans-=query(0,1,'a',x2+y1,x2+y2-1)*(LL)(2*n-x2-y2); 138 ans+=query(0,1,'a',x1+y2-1,x2+y1-1)*(LL)w; 139 ans+=query(1,1,'i',x1-y2+n,x1-y1+n-1); 140 ans-=query(1,1,'a',x1-y2+n,x1-y1+n-1)*(LL)(x1-y2+n-1); 141 ans+=query(1,1,'n',x2-y2+n+1,x2-y1+n); 142 ans-=query(1,1,'a',x2-y2+n+1,x2-y1+n)*(LL)(y1-x2+n-1); 143 ans+=query(1,1,'a',x1-y1+n,x2-y2+n)*(LL)w; 144 } 145 printf("%I64d ",ans); 146 } 147 } 148 } 149 return 0; 150 }
1006 Fang Fang
水题。有c从c开始。没c数f。
!!注意可能有cf以外的字符。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 # define maxn 110000 6 char s[maxn]; 7 8 int main(void) 9 { 10 int T; cin>>T; 11 for(int kase=1;kase<=T;kase++) 12 { 13 scanf("%s",s); 14 int m=strlen(s); 15 int ok=1,pos=0; 16 for(int i=0;i<m;i++) 17 { 18 if(s[i]!='c'&&s[i]!='f') {ok=0;break;} 19 if(s[i]=='c') pos=i; 20 } 21 int mode=0,num=0,ans=0; 22 if(ok) for(int i=0;i<m;i++) 23 { 24 if(s[(pos+i)%m]=='c') 25 { 26 if(mode==1&&num<2) {ok=0;break;} 27 mode=1; ans++; 28 num=0; 29 } 30 else 31 { 32 if(mode==1) num++; 33 else 34 { 35 if(num==0) {ans++; num++;} 36 else num--; 37 } 38 } 39 } 40 if(mode==1&&num<2) ok=0; 41 printf("Case #%d: %d ",kase,ok?ans:-1); 42 } 43 return 0; 44 }
1007 Matches Puzzle Game
1008 Hold Your Hand
1009 Stability
1010 Jesus Is Here
递推。中间过程会用到每个串的长度,串中c的个数,c到左右的距离和。步步取mod。
转移式见代码。
1 # include <iostream> 2 # include <cstdio> 3 using namespace std; 4 # define maxn 222222 5 typedef long long LL; 6 const LL mod=530600414; 7 LL ans[maxn],l[maxn],r[maxn]; 8 LL cnt[maxn],len[maxn]; 9 10 int main(void) 11 { 12 len[1]=1; len[2]=2; len[3]=3; 13 cnt[3]=1; r[3]=2; 14 for(int i=4;i<=201314;i++) 15 { 16 len[i]=(len[i-2]+len[i-1])%mod; 17 cnt[i]=len[i-3]; 18 l[i]=(l[i-2]+l[i-1]+cnt[i-1]*len[i-2])%mod; 19 r[i]=(r[i-2]+r[i-1]+cnt[i-2]*len[i-1])%mod; 20 ans[i]=(ans[i-2]+ans[i-1]+cnt[i-2]*cnt[i-1]+cnt[i-1]*r[i-2]+cnt[i-2]*l[i-1])%mod; 21 } 22 int T; cin>>T; 23 for(int kase=1;kase<=T;kase++) 24 { 25 int x; scanf("%d",&x); 26 printf("Case #%d: %d ",kase,ans[x]); 27 } 28 return 0; 29 }
1011 Poker
1012 Largest Point
1013 Manors