• [luogu8340]山河重整


    记$S$中的元素依次为$a_{1}<a_{2}<...<a_{k}$,考虑对合法的条件进行转化——

    结论:$S$合法当且仅当$\begin{cases}\sum_{i=1}^{k}a_{i}\ge n&(1)\\\forall i\in [1,k],\sum_{j=1}^{i-1}a_{j}+1\ge a_{i}&(2)\end{cases}$

    必要性:若$(1)$不满足则无法得到$n$,若$(2)$不满足则无法得到$\sum_{i=1}^{j-1}a_{j}+1$

    充分性:对于$x\in [1,n]$,从后往前枚举$i$并在$x\ge a_{i}$时将$x$减去$a_{i}$,归纳$x\le \sum_{j=1}^{i}a_{j}$即可

    推论:$S$合法当且仅当$\forall x\in [1,n],S$中$\le x$的元素和$\ne x-1$

    必要性:若$S$中存在$x$的后继$a_{i}$则$\sum_{j=1}^{i-1}a_{j}+1=x<a_{i}$,不存在则$\sum_{i=1}^{k}a_{i}=x-1<n$

    充分性:若$(1)$不满足则取$x=\sum_{i=1}^{k}a_{i}+1$,若$(2)$不满足则取$x=\sum_{j=1}^{i-1}a_{j}+1$

    枚举最小的$x$(不满足条件),记对应的方案数为$f_{x}$,则转移即
    $$
    f_{x}=\{[1,x]子集和为x-1的方案数\}-\sum_{x'=1}^{x-1}\{(x',x]子集和为x-x'的方案数\}f_{x'}
    $$
    另外,答案为$2^{n}-\sum_{x=1}^{n}2^{n-x}f_{x}$

    关于前者,变形得$\sum_{i=1}^{k}a_{i}=\sum_{i=1}^{k}(a_{i}-a_{i-1})(k-i+1)$,且两者一一对应

    记$g_{s}$为$\sum_{i=1}^{k}i\cdot x_{i}=s$的解数(其中$x_{i}\ge 0$且非0的$x_{i}$构成前缀),则方案数也即$g_{x}$

    注意到$k\le \sqrt{2s}$,倒序枚举$k$并对$g$做完全背包(对每个$k$均设初值$g_{0}=1$),时间复杂度为$o(n\sqrt{n})$

    关于后者,可以看作每次设初值为$g_{x'+kx'}=f_{x'}$时的结果,并根据$x'\le \lfloor\frac{x}{2}\rfloor$分治即可

    总复杂度为$o(n\sqrt{n})$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 500005
     4 #define ll long long
     5 int n,mod,ans,pw[N],g[N],f[N];
     6 void add(int &x,int y){
     7     x+=y;if (x>=mod)x-=mod;
     8 } 
     9 void solve(int n){
    10     if (n==1)return;
    11     solve(n>>1);
    12     memset(g,0,sizeof(g));
    13     for(int i=(int)sqrt(n<<1);i;i--){
    14         for(int j=1,s=i+1;(j<=(n>>1))&&(s<=n);j++,s+=i+1)add(g[s],f[j]);
    15         for(int j=n;j>=0;j--)g[j]=(j<i ? 0 : g[j-i]);
    16         for(int j=i;j<=n;j++)add(g[j],g[j-i]);
    17     }
    18     for(int i=(n>>1)+1;i<=n;i++)f[i]=(f[i]-g[i]+mod)%mod;
    19 }
    20 int main(){
    21     scanf("%d%d",&n,&mod);
    22     pw[0]=1;
    23     for(int i=1;i<=n;i++)pw[i]=(pw[i-1]<<1)%mod;
    24     for(int i=(int)sqrt(n<<1);i;i--){
    25         g[0]=1;
    26         for(int j=n;j>=0;j--)g[j]=(j<i ? 0 : g[j-i]);
    27         for(int j=i;j<=n;j++)add(g[j],g[j-i]);
    28     }
    29     for(int i=1;i<=n;i++)f[i]=(i==1 ? 1 : g[i-1]);
    30     ans=pw[n],solve(n);
    31     for(int i=1;i<=n;i++)ans=(ans-(ll)pw[n-i]*f[i]%mod+mod)%mod;
    32     printf("%d\n",ans);
    33     return 0;
    34 }
    View Code
  • 相关阅读:
    poj 1584
    poj 1113 & poj 2187
    pku 1321 棋盘问题
    poj 1408
    pku 2251 Dungeon Master
    sdut oj 2218 Give Me an E
    Android工程 单元测试
    Android Timer编写方式
    去除工程的.svn隐藏文件夹
    Android 绑定远程服务出现 Not Allowed to bind service
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/16282279.html
Copyright © 2020-2023  润新知