[海军国际项目办公室]假人

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[海军国际项目办公室]假人相关的知识,希望对你有一定的参考价值。

假人

题目描述


题解

首先 30 p t s 30pts 30pts的暴力背包 d p dp dp大概是很好想到的,但由于它的复杂度达到了 O ( n 2 k 2 ) O\\left(n^2k^2\\right) O(n2k2),显然是过不了的。
我们根据 k i ⩽ 2 , 3 k_{i}\\leqslant 2,3 ki2,3的两个部分应该很容易想到通过反悔贪心来一步一步求出 t ∈ [ n , ∑ k i ] t\\in[n,\\sum k_{i}] t[n,ki]的答案。
但如果我们将 k k k的范围扩展到 5 5 5,那我们如果采用反悔贪心地话就需要讨论很多种情况,是很难处理的,果断放弃。

由于所有的假话组中都至少要有一个假话被选择,我们可以将 K i K_{i} Ki都减一,此时我们的答案要求的范围也就变成了 [ 0 , ∑ k i ] [0,\\sum k_{i}] [0,ki]
我们定义 d p i dp_{i} dpi表示选择总长度为 i i i的假话,我们可以得到的最大总权值和。
有结论, d p i + 12 − d p i ⩾ d p i + 24 − d p i + 12 dp_{i+12}-dp_{i}\\geqslant dp_{i+24}-dp_{i+12} dpi+12dpidpi+24dpi+12,也就是说在模 12 12 12的意义下,原序列是一个凸包。
事实上着结论出题人也没有给出详尽的证明,但我们可以通过暴力对其进行验证。
C 2020 j z m \\color{black}{C}\\color{red}{2020jzm} C2020jzm的博客有尝试通过暴力对其进行检验的代码。
既然知道了这样的结论,我们可以想到通过分治的方法去求出我们的答案。
对于两个区间,我们可以对它们的 d p dp dp值在模 12 12 12不同的编号下,通过闵可夫斯基和的方式进行求和,进而得到我们完整的区间的 d p dp dp值,其实该方式有点类似于归并,根据极角的大小移动双指针。
我们记 K = 12 K=12 K=12,由于是按 K K K分类合并的,我们总共要进行 K 2 K^2 K2不同类型,而每次合并是 O ( k n K ) O\\left(\\frac{kn}{K}\\right) O(Kkn)
分治合并后直接就可以得到整个区间的答案了。

时间复杂度 O ( K k n log ⁡   n ) O\\left(Kkn\\log\\,n\\right) O(Kknlogn)

源码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;     
const LL INF=0x3f3f3f3f3f3f3f3f;  
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int n1=50;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
    _T f=1;x=0;char s=getchar();
    while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
    while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
    x*=f;
}
template<typename _T>
void print(_T x){putchar('\\n');while(x>9){putchar((x%10)|'0');x/=10;}putchar(x|'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,K[MAXN],a[MAXN][5],idx,siz[MAXN<<2];LL ans,dp[25][MAXN*4],g[MAXN*4];
int sakura(int rt,int l,int r){
    if(l==r){
        int rtp=++idx;siz[rt]=K[l];
        for(int j=0;j<=K[l];j++)dp[rtp][j]=a[l][j];
        return rtp;
    }
    int mid=l+r>>1,lsp,rsp,rtp;
    lsp=sakura(lson,l,mid);rsp=sakura(rson,mid+1,r);siz[rt]=siz[lson]+siz[rson];
    for(int i=0;i<12&&i<=siz[lson];i++)
        for(int j=0;j<12&&j<=siz[rson];j++){
            int k=i+j,i1=i,j1=j;g[k]=max(g[k],dp[lsp][i1]+dp[rsp][j1]);
            while(i1+12<=siz[lson]&&j1+12<=siz[rson]){
                if(dp[lsp][i1+12]-dp[lsp][i1]>dp[rsp][j1+12]-dp[rsp][j1])i1+=12;else j1+=12;
                k+=12;g[k]=max(g[k],dp[lsp][i1]+dp[rsp][j1]);
            } 
            while(i1+12<=siz[lson])i1+=12,k+=12,g[k]=max(g[k],dp[lsp][i1]+dp[rsp][j1]);
            while(j1+12<=siz[rson])j1+=12,k+=12,g[k]=max(g[k],dp[lsp][i1]+dp[rsp][j1]);
        }
    for(int i=0;i<=siz[lson];i++)dp[lsp][i]=0;lsp=0;
    for(int i=0;i<=siz[rson];i++)dp[rsp][i]=0;rsp=0;
    idx-=2;rtp=++idx;for(int i=0;i<=siz[rt];i++)dp[rtp][i]=g[i],g[i]=0;
    return rtp;
}
signed main(){
    read(n);
    for(int i=1;i<=n;i++){
        read(K[i]);K[i]--;
        for(int j=0;j<=K[i];j++)read(a[i][j]);
    }
    int rt=sakura(1,1,n);
    for(int i=0;i<siz[1];i++)printf("%lld ",dp[rt][i]);
    printf("%lld\\n",dp[rt][siz[1]]);
    return 0;
}

谢谢!!!

以上是关于[海军国际项目办公室]假人的主要内容,如果未能解决你的问题,请参考以下文章

[海军国际项目办公室]打拳

[海军国际项目办公室]羽未

[海军国际项目办公室]石子游戏

[海军国际项目办公室]游戏

[海军国际项目办公室]快递

[海军国际项目办公室]生之花