zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",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
    ",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
    ",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
    ");
    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
    ",ans);
    30     return 0;
    31 }
    View Code

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

  • 相关阅读:
    02-0. 整数四则运算(10)
    中国大学MOOC-翁恺-C语言程序设计习题集
    树链剖分
    最小生成树---Prim
    最短路-spfa
    并查集
    Latex学习笔记 第一章
    Javaweb常用解决问题连接
    毕业论文如何排版
    毕业论文指之 “国内外研究现状”的撰写
  • 原文地址:https://www.cnblogs.com/New-Godess/p/4567221.html
Copyright © 2011-2022 走看看