• [atAGC049E]Increment Decrement


    由于每一个操作的逆操作都存在,可以看作将$a_{i}$全部变为0的代价

    先考虑第一个问题,即对于确定的$a_{i}$如何处理

    如果仅能用第2种操作,定义点$i$的代价为以$i$为左端点或以$i-1$为右端点的的操作数,考虑一个代价的意义,即改变$i-1$和$i$的差值,因此$ansge Csum_{i=0}^{n}frac{|a_{i}-a_{i+1}|}{2}$(每一个操作会被算两次)

    (对应的方案只要确保每一次操作减少两对“相邻两数的差值”)

    加入第1种操作,由于操作与顺序无关,不妨先使用第1种操作、后使用第2种操作,假设第1种操作产生的序列为$b_{i}$,则答案为$Csum_{i=0}^{n}|b_{i}-b_{i+1}|+sum_{i=1}^{n}|a_{i}-b_{i}|$(换言之,即找到任意$b_{i}$,最小化该值)

    令$f[i][j]$表示前$i$个数$b_{i}=j$的最小值,转移为$f[i][j]=min(f[i-1][k]+|k-j| imes C)+2|a_{i}-j|$(这里都乘了2避免小数)

    归纳$f[i][j]$具有凸性,转移可以看作找到斜率绝对值大于等于$C$的部分(由于凸性,斜率单调递增,即前后两个区间),将这一部分斜率对$pm C$取max或min

    同时,这也就证明了忽略$2|a_{i}-j|$后$f[i][j]$也具有凸性,而后者具有凸性,因此和也有凸性

    我们直接维护斜率,更严谨的,令$f'[i][j]=f[i][j]-f[i][j-1]$,每一次转移相当于执行以下操作:1.将所有数对$-C$取max,对$C$取min;2.对$[1,a_{i}]$区间减2,对$(a_{i},+infty)$区间加2

    对于$f[i][0]$直接考虑上面的转移,即$f[i][0]=2a_{i}+min_{k}f[i-1][k]+kC$

    简单化简,有$f[i][0]=2a_{i}+f[i-1][0]+min_{k}sum_{j=1}^{k}f'[i-1][j]+C$,而由于$f'[i-1][j]+C$单调递增,后者也可以看作$sum_{j}min(f'[i-1][j]+C,0)$

    答案即求$f[n+1][0]$,可以看作不断累加,即要求出每一次后面的式子对答案的贡献

    由于位置之间相互独立,可以单独去算每一个数的贡献,先对区间离散化(对于$(a_{i-1},a_{i}]$这个区间的贡献显然都相同),再用$dp[i][j]$表示经过前$i$个点后值为$j$的方案数,复杂度为$o(n^{2}k^{2}C)$

    再进一步的,只关心$a_{i}$与枚举的位置的关系,因此可以降为$o(n^{2}kC)$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 105
     4 #define mod 1000000007
     5 vector<pair<int,int> >v;
     6 int n,c,k,x,ans,mi[N],sz[N],sf[N],f[N][N];
     7 int main(){
     8     scanf("%d%d%d",&n,&c,&k);
     9     mi[0]=1;
    10     for(int i=1;i<=n;i++)mi[i]=1LL*mi[i-1]*k%mod;
    11     for(int i=1;i<=n;i++)
    12         for(int j=1;j<=k;j++){
    13             scanf("%d",&x);
    14             v.push_back(make_pair(x,i));
    15             ans=(ans+x)%mod;
    16         }
    17     ans=2LL*ans*mi[n-1]%mod;
    18     sort(v.begin(),v.end());
    19     for(int i=1;i<=n;i++)sf[i]=k;
    20     for(int i=-1,nex=0;i<(int)v.size();i=nex){
    21         while ((i>=0)&&(nex<v.size())&&(v[nex].first==v[i].first)){
    22             sz[v[nex].second]++;
    23             sf[v[nex++].second]--;
    24         }
    25         x=v[nex].first;
    26         if (i>=0)x-=v[i].first;
    27         memset(f,0,sizeof(f));
    28         f[0][2*c+2]=1;
    29         for(int j=0;j<=n;j++)
    30             for(int l=0;l<=2*c+4;l++){
    31                 if (l<2)ans=(ans+1LL*x*(mod+l-2)%mod*f[j][l]%mod*mi[n-j])%mod;
    32                 int ll=min(max(l,2),2*c+2);
    33                 f[j+1][ll+2]=(f[j+1][ll+2]+1LL*sz[j+1]*f[j][l])%mod;
    34                 f[j+1][ll-2]=(f[j+1][ll-2]+1LL*sf[j+1]*f[j][l])%mod;
    35             }
    36     }
    37     ans=1LL*ans*(mod+1)/2%mod;
    38     printf("%d",ans);
    39 }
    View Code
  • 相关阅读:
    socket注意
    PCM音频文件编码
    题外:分类篇(音乐风格分类)基于BP神经网络
    MFCC特征提取过程详解
    语音信号分析
    k-means聚类
    c++关键字详解
    vs中项目解决方案和项目的关系
    条件编译#ifdef 和#endif
    c++快捷键
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14015313.html
Copyright © 2020-2023  润新知