2014 ACM/ICPC Asia Regional Shanghai Online
Tree http://acm.hdu.edu.cn/showproblem.php?pid=5044
树链剖分,区间更新的时候要用on的左++右--的标记方法,要手动扩栈,用c++交,综合以上的条件可过。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #pragma comment(linker, "/STACK:36777216") 5 #define mt(a,b) memset(a,b,sizeof(a)) 6 using namespace std; 7 typedef __int64 LL; 8 const int M=100010; 9 struct G{ 10 struct E{ 11 int v,next; 12 }e[M<<1]; 13 int le,head[M]; 14 void init(){ 15 le=0; 16 mt(head,-1); 17 } 18 void add(int u,int v){ 19 e[le].v=v; 20 e[le].next=head[u]; 21 head[u]=le++; 22 } 23 }g; 24 int n,val[M],fa[M],dep[M],num[M],son[M],top[M],sid[M]; 25 void dfs(int u){ 26 num[u]=1; 27 son[u]=0; 28 for(int i=g.head[u];~i;i=g.e[i].next){ 29 int v=g.e[i].v; 30 if(v!=fa[u]){ 31 fa[v]=u; 32 dep[v]=dep[u]+1; 33 dfs(v); 34 if(num[son[u]]<num[v]) son[u]=v; 35 num[u]+=num[v]; 36 } 37 } 38 } 39 void get(int u,int Top){ 40 sid[u]=++n; 41 top[u]=Top; 42 if(son[u]) get(son[u],top[u]); 43 for(int i=g.head[u];~i;i=g.e[i].next){ 44 int v=g.e[i].v; 45 if(v!=fa[u]&&v!=son[u]){ 46 get(v,v); 47 } 48 } 49 } 50 LL lazy[M],ans[M]; 51 void query(){ 52 LL now=0; 53 for(int i=1;i<=n;i++){ 54 now+=lazy[i]; 55 ans[i]=now; 56 } 57 } 58 void update(int x,int y,int z){ 59 lazy[x]+=z; 60 lazy[y+1]-=z; 61 } 62 void worknode(int x,int y,int z){ 63 int tx=top[x],ty=top[y]; 64 while(tx!=ty){ 65 if(dep[tx]<dep[ty]){ 66 swap(tx,ty); 67 swap(x,y); 68 } 69 update(sid[tx],sid[x],z); 70 x=fa[tx]; 71 tx=top[x]; 72 } 73 if(dep[x]>dep[y]) swap(x,y); 74 update(sid[x],sid[y],z); 75 } 76 void workedge(int x,int y,int z){ 77 int tx=top[x],ty=top[y]; 78 while(tx!=ty){ 79 if(dep[tx]<dep[ty]){ 80 swap(tx,ty); 81 swap(x,y); 82 } 83 update(sid[tx],sid[x],z); 84 x=fa[tx]; 85 tx=top[x]; 86 } 87 if(x==y) return ; 88 if(dep[x]>dep[y]) swap(x,y); 89 update(sid[son[x]],sid[y],z); 90 } 91 struct IN{ 92 int type,u,v,w; 93 }in[M]; 94 struct EDGE{ 95 int u,v; 96 }edge[M]; 97 int main(){ 98 int t,N,m,u,v; 99 while(~scanf("%d",&t)){ 100 int cas=1; 101 while(t--){ 102 scanf("%d%d",&N,&m); 103 g.init(); 104 for(int i=0;i<N-1;i++){ 105 scanf("%d%d",&u,&v); 106 g.add(u,v); 107 g.add(v,u); 108 edge[i].u=u; 109 edge[i].v=v; 110 } 111 n=fa[1]=dep[1]=num[0]=0; 112 dfs(1); 113 get(1,1); 114 char op[8]; 115 for(int i=0;i<m;i++){ 116 scanf("%s%d%d%d",op,&in[i].u,&in[i].v,&in[i].w); 117 if(op[3]=='1') in[i].type=1; 118 else in[i].type=2; 119 } 120 mt(lazy,0); 121 for(int i=0;i<m;i++){ 122 if(in[i].type&1) worknode(in[i].u,in[i].v,in[i].w); 123 } 124 printf("Case #%d:\n",cas++); 125 query(); 126 for(int i=1;i<=N;i++){ 127 if(i>1) printf(" "); 128 printf("%I64d",ans[sid[i]]); 129 } 130 puts(""); 131 mt(lazy,0); 132 for(int i=0;i<m;i++){ 133 if(in[i].type==2) workedge(in[i].u,in[i].v,in[i].w); 134 } 135 query(); 136 for(int i=0;i<N-1;i++){ 137 int u=edge[i].u; 138 int v=edge[i].v; 139 if(dep[u]<dep[v]){ 140 swap(u,v); 141 } 142 if(i) printf(" "); 143 printf("%I64d",ans[sid[u]]); 144 } 145 puts(""); 146 } 147 } 148 return 0; 149 }
Contest http://acm.hdu.edu.cn/showproblem.php?pid=5045
根据题目要求,任意时刻都不能出现两个人做题数量的差大于1,也就是差要<=1,也就是m个问题要分成长度为n的等长的几块,每块里面一人做一个。
问题转化为n个人n题目,如何选一种排列来获得最大价值,若暴力枚举,复杂度是10!,所以用状态压缩,降为2^10,从000推到111.
转移时看哪个人没做过题,那么就可以让他做,状态就是他这位变为1,值就是当前状态的值加上这个人做当前的题目可获得的价值,当前的题目正好等于已做过题的人的个数+1.
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 double a[16][1024],dp[1<<10]; 7 int one(int x){ 8 int res=0; 9 while(x){ 10 if(x&1) res++; 11 x>>=1; 12 } 13 return res; 14 } 15 int main(){ 16 int t,n,m; 17 while(~scanf("%d",&t)){ 18 int cas=1; 19 while(t--){ 20 scanf("%d%d",&n,&m); 21 for(int i=0;i<n;i++){ 22 for(int j=0;j<m;j++){ 23 scanf("%lf",&a[i][j]); 24 } 25 } 26 int s=0,num,all=1<<n; 27 bool flag=true; 28 double ans=0; 29 while(flag){ 30 flag=false; 31 if(s+n<m){ 32 flag=true; 33 num=n; 34 } 35 else{ 36 num=m-s; 37 } 38 mt(dp,0); 39 for(int i=0;i<all;i++){ 40 int yi=one(i); 41 if(yi>=num) continue; 42 for(int j=0;j<n;j++){ 43 if((i>>j)&1) continue; 44 int next=i|(1<<j); 45 dp[next]=max(dp[next],dp[i]+a[j][s+yi]); 46 } 47 } 48 double big=0; 49 if(num==n){ 50 big=dp[all-1]; 51 } 52 else{ 53 for(int i=0;i<all;i++){ 54 if(one(i)==num){ 55 big=max(big,dp[i]); 56 } 57 } 58 } 59 ans+=big; 60 s+=n; 61 } 62 printf("Case #%d: %.5f\n",cas++,ans); 63 } 64 } 65 return 0; 66 }
Sawtooth http://acm.hdu.edu.cn/showproblem.php?pid=5047
根据另一个类似的题目可以猜想出,这种分割方法出来的平面个数应该是个一元二次函数,a*x^2+b*x+c,过3个点,0的时候是1个平面,题目还输入两组,三个进去解出方程的abc,然后输入x就可以输出值了。
1 #include<cstdio> 2 #include<cstring> 3 #define mt(a,b) memset(a,b,sizeof(a)) 4 const int M=32; 5 class Hp { //高精度类 6 int len,s[M]; 7 public: 8 void init(char ch[]) { 9 len=1; 10 mt(s,0); 11 int i=0; 12 while(ch[i]=='0'&&ch[i]!=0) i++; 13 if(ch[i]!=0) { 14 len=strlen(ch)-i; 15 for(i=0; i<len; i++) { 16 s[i]=ch[len-i-1]-48; 17 } 18 } 19 } 20 void print() { //输出 21 int i=len-1; 22 while(s[i]==0&&i>0) i--; 23 for(; i>=0; i--) { 24 printf("%d",s[i]); 25 } 26 } 27 void add(int x) { //高精度加单精度 28 int temp=0; 29 s[0]+=x; 30 while(s[temp]>9) { 31 s[temp]-=10; 32 temp++; 33 s[temp]++; 34 } 35 if(s[len]!=0) len++; 36 } 37 void subtract(Hp a) { //高精度减高精度 38 for(int i=0; i<len; i++) { 39 s[i]-=a.s[i]; 40 if(s[i]<0) { 41 s[i]+=10; 42 s[i+1]--; 43 } 44 } 45 while(len>1&&s[len-1]==0) len--; 46 } 47 void multiply(int b) { //高精度乘单精度 48 int temp=0; 49 for(int i=0; i<len; i++) { 50 temp+=s[i]*b; 51 s[i]=temp%10; 52 temp/=10; 53 } 54 s[len++]=temp; 55 while(s[len-1]>10) { 56 s[len]+=s[len-1]/10; 57 s[len-1]%=10; 58 len++; 59 } 60 while(len>1&&s[len-1]==0) len--; 61 } 62 void multiply(Hp b) { //高精度乘高精度 63 Hp c; 64 mt(c.s,0); 65 for(int i=0; i<len; i++) { 66 for(int j=0; j<b.len; j++) { 67 c.s[i+j]+=s[i]*b.s[j]; 68 c.s[i+j+1]+=c.s[i+j]/10; 69 c.s[i+j]%=10; 70 } 71 } 72 len=len+b.len; 73 for(int i=0; i<len; i++) { 74 s[i]=c.s[i]; 75 } 76 while(len>1&&s[len-1]==0) len--; 77 } 78 } A,B; 79 char a[M]; 80 int main(){ 81 int t; 82 while(~scanf("%d",&t)){ 83 int cas=1; 84 while(t--){ 85 scanf("%s",a); 86 A.init(a); 87 B.init(a); 88 A.multiply(B); 89 A.multiply(8); 90 B.multiply(7); 91 A.subtract(B); 92 A.add(1); 93 printf("Case #%d: ",cas++); 94 A.print(); 95 puts(""); 96 } 97 } 98 return 0; 99 }
那个类似的题目被我找到了
折线分割平面 http://acm.hdu.edu.cn/showproblem.php?pid=2050
一样的解一元二次
1 #include<cstdio> 2 int main(){ 3 int t,n; 4 while(~scanf("%d",&t)){ 5 while(t--){ 6 scanf("%d",&n); 7 printf("%d\n",2*n*n-n+1); 8 } 9 } 10 return 0; 11 }
end