zoukankan      html  css  js  c++  java
  • CF1485X Codeforces Round #701

    D Multiples and Power Differences (构造)

    题目大意:给一个n*m的矩阵a,a[i][j]在1到16之间。现在要构造矩阵b,需要满足如下条件:

    1.b[i][j]在1到1e6之间

    2.b[i][j]是a[i][j]的倍数

    3.对于矩阵中任意相邻的两个数,要求存在正整数k,他们的差值绝对值等于k的四次方,不要求所有对的k都相同

    构造神仙题,乍一看不可做。。

    考虑第二个条件,由于a最多到16,发现1到16所有数的最小公倍数是$720720$!小于1e6。

    在考虑第三个条件,可以对b矩阵黑白染色,黑点构造成$720720+a[i][j]^{4}$,白点是$720720$

    矩阵问题不仅可以建边跑图论,还可以染色处理

     1 const int N1=505; const int maxn=720720;
     2 
     3 int n,m;
     4 int a[N1][N1],b[N1][N1];
     5 
     6 int main()
     7 {
     8     freopen("a.in","r",stdin);
     9     scanf("%d%d",&n,&m);
    10     for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]);
    11     for(int i=1;i<=n;i++,puts("")) for(int j=1;j<=m;j++) 
    12     {
    13         if((i+j)%2==0){
    14             b[i][j]=maxn;
    15         }else{
    16             b[i][j]=maxn+a[i][j]*a[i][j]*a[i][j]*a[i][j];
    17         }
    18         printf("%d ",b[i][j]);
    19     }
    20     return 0;
    21 }
    View Code

    E Move and Swap (树形DP)

    题目大意:给你一棵有根树,开始时有红蓝两个棋子放在根上,一次移动需要进行如下操作:

    设红蓝棋子当前未知分别为r,b

    1.把红棋子移动到r的某个子节点上

    2.把蓝棋子移动到深度=dep[b]+1的某个点上

    3.可选择是否交换红蓝棋子的位置

    每次移动产生$|a[r]-a[b]|$点代价,现在求代价之和的最大值

    对点按深度从大到小依次处理

    令$f[i]$表示$i$节点放红色棋子时的最大贡献,$g[j]$表示$j$子节点中$f$的最大值

    可得转移方程$f[i]=maxleft { max(g[i],g[j])+|a[i]-a[j]| ight } $  

    将相同深度的点按a排序,正反各计算一次,即可消掉绝对值,再用前缀/后缀最大值优化转移即可

     1 const int N1=200005; const ll inf=0x3f3f3f3f3f3f3f3fll;
     2 
     3 int n,T;
     4 struct EDGE{
     5 int to[N1],nxt[N1],head[N1],cte;
     6 void ae(int u,int v)
     7 { cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; } 
     8 }e;
     9 
    10 ll f[N1],g[N1];
    11 int fa[N1],a[N1],dep[N1],madep;
    12 vector<int>id[N1];
    13 int cmp1(int x,int y){ return a[x]<a[y]; }
    14 void clr()
    15 {
    16     for(int i=1;i<=n;i++) e.head[i]=0, id[i].clear(), f[i]=g[i]=dep[i]=0;
    17     while(e.cte) e.to[e.cte]=e.nxt[e.cte]=0, e.cte--; 
    18 }
    19 
    20 void dfs(int u)
    21 {
    22     for(int j=e.head[u];j;j=e.nxt[j])
    23     {
    24         int v=e.to[j]; dep[v]=dep[u]+1; madep=max(madep,dep[v]);
    25         id[dep[v]].push_back(v);
    26         dfs(v);
    27     }
    28 }
    29 
    30 int main()
    31 {
    32     freopen("a.in","r",stdin);
    33     scanf("%d",&T);
    34     while(T--){
    35 
    36     scanf("%d",&n);
    37     for(int i=2;i<=n;i++) scanf("%d",&fa[i]), e.ae(fa[i],i);
    38     for(int i=2;i<=n;i++) scanf("%d",&a[i]);
    39     madep=0; dfs(1);
    40     ll tma,ma;
    41     for(int k=madep,i;k>=1;k--)
    42     {
    43         sort(id[k].begin(),id[k].end(),cmp1);
    44         tma=-inf; ma=-inf;
    45         for(int j=0;j<id[k].size();j++)
    46         {
    47             i=id[k][j]; tma=max(tma,g[i]-a[i]); ma=max(ma,-1ll*a[i]);
    48             f[i]=max(tma+a[i],g[i]+a[i]+ma);
    49         }
    50         tma=-inf; ma=-inf;
    51         for(int j=(int)id[k].size()-1;j>=0;j--)
    52         {
    53             i=id[k][j]; tma=max(tma,g[i]+a[i]); ma=max(ma,1ll*a[i]);
    54             f[i]=max(f[i],max(tma-a[i],g[i]+ma-a[i]));
    55         }
    56         for(int j=0;j<id[k].size();j++)
    57         {
    58             i=id[k][j]; g[fa[i]]=max(g[fa[i]],f[i]);
    59         }
    60     }
    61     printf("%lld
    ",g[1]);
    62     clr();
    63 
    64     }
    65     return 0;
    66 }
    View Code

    F Copy or Prefix Sum (线段树优化DP)

    题目大意:给定数组b,现在求有多少满足如下条件的a数组:

    $b[i]=a[i]$或$b[i]=sum_{j=1}^{i}a[j]$

    考场上最后一分钟调出来了,结果我非得给数组多按个0然后CE(MLE)了。。不然就不会掉分了

    发现第二个条件是前缀和比较特殊,并且第一个条件不影响答案

    考虑DP选择第二个条件的位置

    定义f[i]表示i位置满足第二个条件且不满足第一个条件时的方案数

    不满足第一个条件时$b[i] e a[i]$,计算可得$sum[i-1]-sum[j-1] e 0$

    $f[i]=sum_{j=1}^{i-1}f[j](sum[i-1] e sum[j-1])$

    线段树优化DP就好了!又由于sum值域较大且可能为负,动态开点+整体往右挪

     1 const int N1=200005; const int inf=0x3f3f3f3f;
     2 const ll maxn=1e15;
     3 const int p=1000000007;
     4 
     5 int T,n;
     6 int a[N1],b[N1];
     7 ll f[N1];
     8 struct SEG{
     9 ll sum[N1*65]; int ls[N1*65],rs[N1*65],tot;
    10 void pushup(int rt){ sum[rt]=(sum[ls[rt]]+sum[rs[rt]])%p; }
    11 void upd(ll x,ll l,ll r,int &rt,ll w)
    12 {
    13     if(!rt) rt=++tot;
    14     if(l==r){ (sum[rt]+=w)%=p; return; }
    15     ll mid=(l+r)>>1;
    16     if(x<=mid) upd(x,l,mid,ls[rt],w);
    17     else upd(x,mid+1,r,rs[rt],w);
    18     pushup(rt);
    19 }
    20 ll query(ll L,ll R,ll l,ll r,int rt)
    21 {
    22     if(!rt) return 0;
    23     if(L<=l&&r<=R) return sum[rt];
    24     ll mid=(l+r)>>1; ll ans=0;
    25     if(L<=mid) ans+=query(L,R,l,mid,ls[rt]);
    26     if(R>mid) ans+=query(L,R,mid+1,r,rs[rt]);
    27     ans%=p;
    28     return ans;
    29 }
    30 void clr()
    31 {
    32     while(tot) sum[tot]=0, ls[tot]=rs[tot]=0, tot--;    
    33 }
    34 }s;
    35 ll sum[N1];
    36 
    37 int main()
    38 {
    39     scanf("%d",&T);
    40     ll ans=0,mi=maxn,ma=-maxn;
    41     while(T--)
    42     {
    43         scanf("%d",&n); 
    44         for(int i=1;i<=n;i++) scanf("%d",&b[i]), sum[i]=sum[i-1]+b[i], mi=min(mi,sum[i]), ma=max(ma,sum[i]);
    45         ll ans=1; f[1]=0; int root=0;
    46         for(int i=2;i<=n;i++)
    47         {
    48             // f[i]=1;
    49             if(sum[i-1]!=0) f[i]=1; else f[i]=0;
    50             // for(int j=1;j<i;j++) if(sum[i-1]!=sum[j-1])
    51             //     (f[i]+=f[j])%=p;
    52             if(mi<sum[i-1]) (f[i]+=s.query(mi+maxn,sum[i-1]+maxn-1,mi+maxn,ma+maxn,root));
    53             if(sum[i-1]<ma) (f[i]+=s.query(sum[i-1]+maxn+1,ma+maxn,mi+maxn,ma+maxn,root));
    54             f[i]%=p;
    55             s.upd(sum[i-1]+maxn,mi+maxn,ma+maxn,root,1ll*f[i]);
    56             (ans+=f[i])%=p;
    57         }
    58         printf("%lld
    ",ans);
    59         s.clr();
    60     }
    61     return 0;
    62 }
    View Code
  • 相关阅读:
    2019春第十一周作业
    2019春第十周作业
    2019春第九周作业
    2019春第八周作业
    2019春第七周作业
    2019春第六周作业
    寒假作业一:打印沙漏
    寒假作业三:抓老鼠啊亏了~还是赚了?
    寒假作业二:币值转换
    秋季学期学习总结
  • 原文地址:https://www.cnblogs.com/guapisolo/p/14399910.html
Copyright © 2011-2022 走看看