Codeforce 水题报告(2)

又水了一发Codeforce ,这次继续发发题解顺便给自己PKUSC攒攒人品吧

CodeForces 438C:The Child and Polygon:

描述:给出一个多边形,求三角剖分的方案数(n<=200)。

首先很明显可能是区间dp,我们可以记f[i][j]为从i到j的这个多边形的三角剖分数,那么f[i][j]=f[i][k]*f[j][k]*(i,j,k是否为1个合格的三角形)

Code:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef pair<double,double> ii;
 7 #define fi first
 8 #define se second
 9 #define maxn 410
10 #define mod 1000000007
11 int f[maxn][maxn],n;
12 ii a[maxn];
13 inline double cross(ii x,ii y,ii z) {
14     return (y.fi-x.fi)*(z.se-x.se)-(y.se-x.se)*(z.fi-x.fi);
15 }
16 inline bool check() {
17     double ans=0;
18     for (int i=2;i<=n;i++) ans+=cross(a[1],a[i-1],a[i]);
19     return ans>0;
20 }
21 inline void revice(){
22     for (int i=1,j=n;i<j;i++,j--) swap(a[i],a[j]);
23 }
24 int main(){
25     scanf("%d",&n);
26     for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].fi,&a[i].se);
27     if (check()) revice();
28     for (int i=1;i+1<=n;i++) f[i][i+1]=1;    
29     for (int l=1;l<=n-1;l++) 
30         for (int i=1;i+l<=n;i++)
31             for (int j=i+1;j<i+l;j++) 
32                 (f[i][i+l]+=f[i][j]*1ll*f[j][i+l]%mod*(cross(a[i],a[j],a[i+l])<0?1:0))%=mod;
33     printf("%d\n",f[1][n]);
34     return 0;
35 }
View Code

CodeForces 438D:The Child and Sequence

描述:给一个序列,要求支持区间取模,区间求和,单点修改(n<=10^5)

考虑如何用线段树来搞这个东西,很明显对于所有区间取模操作都必须用搞到点,但是如果我们加入一个小优化(只有区间序列的最大值大于那个区间的话,才往下传递)然后我们就可以解决这个问题啦。

为啥?我们可以发现当一个数取模的时候至少变小一半,因此每个数最多取模log a[i]次,所以总的时间复杂度为n log^2 n

Code:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 #define maxn 101000
 7 typedef long long ll;
 8 struct node {
 9     int l,r,lz,mx;bool b;ll s;
10 }t[maxn*8];
11 int a[maxn];
12 #define lc (x<<1)
13 #define rc (lc^1)
14 #define mid ((l+r)>>1)
15 inline void update(int x){
16     t[x].s=t[lc].s+t[rc].s;
17     t[x].mx=max(t[lc].mx,t[rc].mx);
18     t[x].b=t[lc].b&t[rc].b;
19 }
20 inline void pb(int x) {
21     if (!t[x].lz) return ;
22     if (t[x].l==t[x].r) {
23         t[x].b=1;t[x].lz=0;return ;
24     }
25     pb(lc);pb(rc);
26     if (t[lc].mx>=t[x].lz) {
27         t[lc].mx%=t[x].lz;
28         t[lc].lz=t[x].lz;
29         t[lc].s%=t[x].lz;
30         t[lc].b=0;
31     }if (t[rc].mx>=t[x].lz) {
32         t[rc].mx%=t[x].lz;
33         t[rc].lz=t[x].lz;
34         t[rc].s%=t[x].lz;
35         t[rc].b=0;
36     }
37     t[x].lz=0;
38     update(x);
39 }
40 void build(int x,int l,int r) {
41     t[x].l=l,t[x].r=r;
42     t[x].lz=0;t[x].b=1;
43     if (l==r) {t[x].s=t[x].mx=a[l];return ;}
44     build(lc,l,mid);build(rc,mid+1,r);
45     update(x);
46 }
47 ll sum(int x,int x1,int y1) {
48     int l=t[x].l,r=t[x].r;
49     if (y1<l||x1>r) return 0;
50 //    pb(x);
51     if (x1<=l&&r<=y1) return t[x].s;
52     ll ans=sum(lc,x1,y1)+sum(rc,x1,y1);
53     update(x);
54     return ans;
55 }
56 void set(int x,int y,int z){
57     int l=t[x].l,r=t[x].r;
58     if (l>y||r<y) return;
59     if (l==r) {t[x].s=t[x].mx=z;return ;}
60 //    pb(x);
61     set(lc,y,z);set(rc,y,z);
62     update(x);
63 }
64 void mod(int x,int x1,int y1,int z){
65     int l=t[x].l,r=t[x].r;
66     if (y1<l||x1>r) return ;
67 //    pb(x);
68     if (t[x].mx<z) return ;
69     if (l==r) {
70         t[x].mx%=z;t[x].s%=z;return ;
71     }
72     mod(lc,x1,y1,z);mod(rc,x1,y1,z);
73     update(x);
74 }
75 int main(){
76     int n,m;
77     scanf("%d%d",&n,&m);
78     for (int i=1;i<=n;i++) scanf("%d",a+i);
79     build(1,1,n);
80     while (m--) {
81         int opt,l,r,x,y;
82         scanf("%d",&opt);
83         switch(opt) {
84             case 1:
85                 scanf("%d%d",&l,&r);
86                 printf("%I64d\n",sum(1,l,r));
87                 break;
88             case 2:
89                 scanf("%d%d%d",&l,&r,&x);
90                 mod(1,l,r,x); 
91                 break;
92             case 3:
93                 scanf("%d%d",&x,&y);
94                 set(1,x,y);
95                 break;
96         }
97     }
98     return 0;
99 }
View Code

CodeForces 434D:Nanami's Power Plant

描述:有n个节点,每个节点可以取一个xi(li<=xi<=ri)xi为整数,然后对于每个节点的权值为ai*x^2+bi*x同时需要满足某些xu-xv<=w的限制

既然是整数那么我们就可以直接用网络流啦,对每个节点的每个取值拆下,然后连边权为权值的边,然后就是最小割啦。接下来再考虑那些限制的条件,我们可以对所有相邻的东西可以直接连一个x[u]->x[v]+w,流量为inf的边,就可以限制到啦

Code:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 #define maxn 15100
 7 #define maxm 250000
 8 struct edges{
 9     int to,next,cap;
10 }edge[maxm*2];
11 int next[maxn],L,Cnt;
12 #define inf 0x7fffffff
13 inline void addedge(int x,int y,int z){
14     L++;
15     edge[L*2]=(edges){y,next[x],z};next[x]=L*2;
16     edge[L*2+1]=(edges){x,next[y],0};next[y]=L*2+1;
17 }
18 int h[maxn],gap[maxn],p[maxn],s,t;
19 int sap(int u,int flow){
20     if (u==t) return flow;
21     int cnt=0;
22     for (int i=p[u];i;i=edge[i].next) 
23         if (edge[i].cap&&h[edge[i].to]+1==h[u]) {
24             int cur=sap(edge[i].to,min(flow-cnt,edge[i].cap));
25             edge[i].cap-=cur;edge[i^1].cap+=cur;
26             p[u]=i;
27             if ((cnt+=cur)==flow) return flow;
28         }
29     if (!(--gap[h[u]])) h[s]=Cnt;
30     gap[++h[u]]++;p[u]=next[u];
31     return cnt;
32 }
33 inline int maxflow(){
34     for (int i=1;i<=Cnt;i++) p[i]=next[i];
35     memset(h,0,sizeof(h));
36     memset(gap,0,sizeof(gap));
37     gap[0]=Cnt;
38     int flow=0;
39     while (h[s]<Cnt) flow+=sap(s,inf);
40     return flow;
41 }
42 #define maxk 55
43 int a[maxk],b[maxk],c[maxk],st[maxk];
44 int l[maxk],r[maxk];
45 inline int fun(int x,int y) {return a[x]*y*y+b[x]*y+c[x];}
46 inline int id(int x,int y) {return st[x]+y-l[x];}
47 int main(){
48     int n,m,mx=0;
49     scanf("%d%d",&n,&m);
50     s=++Cnt,t=++Cnt;
51     for (int i=1;i<=n;i++) scanf("%d%d%d",a+i,b+i,c+i);
52     for (int i=1;i<=n;i++) {
53         scanf("%d%d",l+i,r+i);
54         st[i]=Cnt+1;
55         Cnt+=r[i]-l[i]+2;
56         for (int j=l[i];j<=r[i];j++) mx=max(mx,fun(i,j));
57     }
58     for (int i=1;i<=n;i++) {
59         addedge(s,id(i,l[i]),inf);
60         for (int j=l[i];j<=r[i];j++) addedge(id(i,j),id(i,j+1),mx-fun(i,j));
61         addedge(id(i,r[i]+1),t,inf);
62     }
63     while (m--) {
64         int u,v,d;
65         scanf("%d%d%d",&u,&v,&d);
66         for (int i=l[u];i<=r[u];i++) 
67             if (i-d>=l[v]&&i-d<=r[v]+1)    
68                 addedge(id(u,i),id(v,i-d),inf);
69     }
70     printf("%d\n",mx*n-maxflow());
71 }
View Code

CodeForces 543C:Remembering Strings

描述:给定一堆字符串,改变某个字符需要一定的花费,求使所有的字符串都是好记的(存在一位的字符是该位中的唯一一个)(n<=20,len<=20)

很神奇的一道题,考虑用数位dp来解决这道题。我们考虑如何使一个字符串变成好记的,很简单只要改变某一位的字符即可,或者需要把这种字符都改变的话,那么花费是sum-mx(除了花费最大的不变,其他都需要改变)然后就行啦

实现的话用了一直比较鬼畜的写法,结果意外的短,详情可以看代码

Code:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cstring>
 6 using namespace std;
 7 #define maxn 23 
 8 char s[23][23];
 9 int f[1<<21],a[23][23];
10 int n;
11 inline int lowbit(int x) {
12     for (int i=0;i<n;i++) if (!((1<<i)&x)) return i;
13 }
14 int main(){
15     int m;
16     scanf("%d%d",&n,&m);
17     for (int i=0;i<n;i++) scanf("%s",s[i]+1);
18     for (int i=0;i<n;i++) 
19         for (int j=1;j<=m;j++) scanf("%d",&a[i][j]);
20     memset(f,0x3f,sizeof(f));
21     f[0]=0;
22     for (int i=0;i<(1<<n)-1;i++) {
23         int x=lowbit(i);
24         for (int j=1;j<=m;j++) {
25             f[i|(1<<x)]=min(f[i|(1<<x)],f[i]+a[x][j]);
26             int y=0,sum=0,mx=0;
27             for (int k=0;k<n;k++) {
28                 if (s[x][j]==s[k][j]) {
29                     y|=1<<k;
30                     sum+=a[k][j];
31                         mx=max(a[k][j],mx);
32                 }
33             }
34             f[i|y]=min(f[i|y],f[i]+sum-mx);
35         }
36     }
37     printf("%d\n",f[(1<<n)-1]);
38     return 0;
39 }
View Code

CodeForces 543D:Road Improvement

已知有一颗树,对所有点求删去某些边,使得其他点到该点至多经过一条坏边的方案数(n<=2*10^5)

很明显是树形dp,那么f[x]=pai(f[ch[x]]+1)

考虑怎么从祖先的答案算出自己的答案,很明显吧自己除去就能把祖先当自己的子树干了

除的时候不能直接用乘法逆元(f[x]可能为0 ), 需要存一个前缀和还有后缀和

Code:

 1     #include<cstdio>
 2     #include<iostream>
 3     #include<cstring>
 4     #include<algorithm>
 5     #include<vector>
 6     using namespace std;
 7     typedef long long ll;
 8     #define maxn 200100
 9     #define mod 1000000007
10     vector<int> e[maxn];
11     vector<ll> s[2][maxn];
12     #define pb push_back
13     ll f[maxn],sum[maxn];
14     int ans[maxn],fa[maxn];
15     inline ll power(ll x,int y){
16         ll ans=1;
17         for (;y;y>>=1) {
18             if (y&1) (ans*=x)%=mod;
19             (x*=x)%=mod;
20         }
21         return ans;
22     }
23     int q[maxn];
24     int main(){
25         int n;
26         scanf("%d",&n);
27         if (n==1) {printf("%d\n",0);return 0;}
28         for (int i=2;i<=n;i++) {
29             scanf("%d",fa+i);
30             e[fa[i]].pb(i);
31         }
32         q[1]=1;
33         for (int l=1,r=1,u=q[1];l<=r;u=q[++l]) {
34             for (int i=0;i<e[u].size();i++) q[++r]=e[u][i];
35         }
36         for (int r=n,u=q[n];r;u=q[--r]) {
37             ll sum=1;
38             s[1][u].resize(e[u].size());
39             s[0][u].resize(e[u].size());
40             for (int i=0;i<e[u].size();i++) {
41                 s[1][u][i]=sum;
42                 (sum*=f[e[u][i]]+1)%=mod;
43             }
44             sum=1;
45             for (int i=e[u].size()-1;i+1;i--) {
46                 s[0][u][i]=sum;
47                 (sum*=f[e[u][i]]+1)%=mod;
48             }
49             f[u]=sum;
50         }
51         sum[1]=0;
52         for (int l=1,u=q[1];l<=n;u=q[++l]) {
53             ans[u]=f[u]*(sum[u]+1)%mod;
54             for (int i=0;i<e[u].size();i++) 
55                 sum[e[u][i]]=s[0][u][i]*s[1][u][i]%mod*(sum[u]+1)%mod;
56         }
57         for (int i=1;i<=n;i++) printf("%d ",ans[i]);
58         return 0;
59     }
View Code

CodeForces 546E:Soldier and Traveling

描述:有n个城市和m条道路,每个城市有一定的士兵,士兵可以移动到相邻的城市,求是否存在一种移动方式使得每个城市的驻兵数为某个值(n<=100,m<=200)

很明显是网络流吧,拆点然后随便搞搞即可

Code:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 #define maxn 300
 7 #define maxm 10000
 8 struct edges{
 9     int to,next,cap;
10 }edge[maxm*2];
11 int next[maxn],L,Cnt;
12 #define inf 0x7fffffff
13 inline void addedge(int x,int y,int z){
14     L++;
15     edge[L*2]=(edges){y,next[x],z};next[x]=L*2;
16     edge[L*2+1]=(edges){x,next[y],0};next[y]=L*2+1;
17 }
18 int h[maxn],gap[maxn],p[maxn],s,t;
19 int sap(int u,int flow){
20     if (u==t) return flow;
21     int cnt=0;
22     for (int i=p[u];i;i=edge[i].next) 
23         if (edge[i].cap&&h[edge[i].to]+1==h[u]) {
24             int cur=sap(edge[i].to,min(flow-cnt,edge[i].cap));
25             edge[i].cap-=cur;edge[i^1].cap+=cur;
26             p[u]=i;
27             if ((cnt+=cur)==flow) return flow;
28         }
29     if (!(--gap[h[u]])) h[s]=Cnt;
30     gap[++h[u]]++;p[u]=next[u];
31     return cnt;
32 }
33 inline int maxflow(){
34     for (int i=1;i<=Cnt;i++) p[i]=next[i];
35     memset(h,0,sizeof(h));
36     memset(gap,0,sizeof(gap));
37     gap[0]=Cnt;
38     int flow=0;
39     while (h[s]<Cnt) flow+=sap(s,inf);
40     return flow;
41 }
42 #define maxk 110
43 int a[maxk][2],ans[maxk][maxk];
44 int main(){
45     freopen("1.in","r",stdin);
46     int n,m,sum=0,tmp=0;
47     scanf("%d%d",&n,&m);
48     s=++Cnt,t=++Cnt;
49     for (int i=1;i<=n;i++) a[i][0]=++Cnt,a[i][1]=++Cnt;
50     for (int i=1;i<=n;i++) {
51         int x;
52         scanf("%d",&x);
53         tmp+=x;
54         addedge(s,a[i][0],x);    
55     }
56     for (int i=1;i<=n;i++) {
57         int x;
58         scanf("%d",&x);
59         sum+=x;
60         addedge(a[i][0],a[i][1],inf);
61         addedge(a[i][1],t,x);
62     }
63     for (int i=1;i<=m;i++) {
64         int x,y;
65         scanf("%d%d",&x,&y);
66         addedge(a[x][0],a[y][1],inf);
67         addedge(a[y][0],a[x][1],inf);
68     }
69     if (maxflow()!=sum||sum!=tmp) {
70         printf("NO\n");
71         return 0;
72     }
73     puts("YES");
74     for (int i=1;i<=L;i++) {
75         ans[(edge[i*2+1].to-1)>>1][(edge[i*2].to-1)>>1]=edge[i*2+1].cap;
76     }
77     for (int i=1;i<=n;i++,puts("")) 
78         for (int j=1;j<=n;j++) printf("%d ",ans[i][j]);
79     return 0;
80 }
View Code

CodeForces 534D:Handshakes

描述:有个房子,有n个人按顺序进去,一个人进去就会跟房间中空闲的人握手,每3个人可以组队做事,给定握手数,求方案

我们从0开始,每次看+1的有没有人,没有就-3,完了

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stack>
 6 using namespace std;
 7 #define maxn 201000
 8 stack<int> s[maxn];
 9 int ans[maxn];
10 int main(){
11     int n,x;
12     scanf("%d",&n);
13     for (int i=1;i<=n;i++) {
14         scanf("%d",&x);
15         s[x].push(i);
16     }
17     int t=0,cnt=0;
18     while (t>=0) {
19         if (s[t].empty()) {t-=3;continue;}
20         ans[++cnt]=s[t].top();s[t].pop();t++;
21     }
22     if (cnt!=n) {
23         puts("Impossible");
24         return 0;
25     }
26     puts("Possible");
27     for (int i=1;i<=n;i++) printf("%d ",ans[i]);
28     return 0;
29 }
View Code

CodeForces 545E:Paths and Trees

给定一个图,求权值和最小的最短路树

那么最短路图建好,模拟克鲁斯卡尔算法,拍个序,又由于是个有向树,所以除了点u外都只有一个父亲,维护这个性质即可

CodeForces 542F:Quest

给定若干个节点作为二叉树的儿子节点,每个节点有其深度限制及权值,求构建一颗二叉树,使其权值最大

按深度限制从大到小干,每次把两个最大的合成一个小的即可

Code:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 #define maxn 110
 8 priority_queue<int> q[maxn];
 9 int main(){
10     int n,t,x,y;
11     freopen("1.in","r",stdin);
12     scanf("%d%d",&n,&t);
13     for (int i=1;i<=n;i++) {
14         scanf("%d%d",&x,&y);
15         q[x].push(y);
16     }
17     int ans=0;
18     for (int i=1;i<=t;i++) {
19         while (!q[i-1].empty()) {
20             int u=q[i-1].top();q[i-1].pop();
21             if (!q[i-1].empty()) {
22                 u+=q[i-1].top();
23                 q[i-1].pop();
24             }
25             q[i].push(u);
26         }
27         if (!q[i].empty()) ans=max(ans,q[i].top());
28     }
29     printf("%d\n",ans);
30     return 0;
31 }
View Code

好了就写到这里啦,代码回来再贴。回去收东西啦。

posted @ 2015-06-10 20:37  New_Godess  阅读(290)  评论(0编辑  收藏  举报