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 }
View Code

 

 

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 }
View Code

 

 

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 }
View Code

 那个类似的题目被我找到了

折线分割平面 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 }
View Code

 

 

 

end

posted on 2014-09-27 18:10  gaolzzxin  阅读(282)  评论(0编辑  收藏  举报