zoukankan      html  css  js  c++  java
  • [BZOJ2655] calc

    题目链接

    BZOJ:https://www.lydsy.com/JudgeOnline/problem.php?id=2655

    Solution

    (f_i)表示长度为(i)的序列个数,(g_{i,x})表示含有(x)的序列个数,注意这里不考虑顺序,顺序答案直接乘(n!)就好了。

    首先很显然可以得到:

    [f_i=frac{1}{n}sum_{x=1}^{A}g_{i,x} ]

    我们尝试向(f_i)中添加一个(x),可以得到:

    [xf_i=xg_{i,x}+g_{i+1,x} ]

    把这个式子变一下:

    [g_{i,x}=xf_{i-1}-xg_{i-1,x} ]

    注意到这是个递归的形式,可以得到:

    [g_{n,x}=sum_{i=1}^{n}(-1)^{i-1}x^if_{n-i} ]

    根据第一个式子累和:

    [f_n=frac{1}{n}sum_{i=1}^Ag_{n,x}=frac{1}{n}sum_{i=1}^{A}sum_{j=1}^{n}(-1)^{j-1}i^{j}f_{n-j}=frac{1}{n}sum_{j=1}^{n}left((-1)^{j-1}sum_{i=1}^{A}i^j ight)f_{n-j} ]

    注意中间是一个只和(j)有关的式子,我们可以插值做到(O(n))算一次。

    那么我们预处理中间,其他的爆算就好了,复杂度(O(n^2))

    注意我代码偷懒多了个(log),但是不影响。

    #include<bits/stdc++.h>
    using namespace std;
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    #define ll long long 
    
    #define pii pair<int,int >
    #define vec vector<int >
    
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
    
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++) 
    
    const int maxn = 600+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    
    int g[maxn],f[maxn],y[maxn],mod,fac[maxn],ifac[maxn],inv[maxn],suf[maxn],pre[maxn];
    
    int qpow(int a,int x) {
        int res=1;
        for(;x;x>>=1,a=1ll*a*a%mod) if(x&1) res=1ll*res*a%mod;
        return res;
    }
    
    int power_sum(int n,int k) {
        fac[0]=ifac[0]=1;k+=2;
        for(int i=1;i<=k;i++) y[i]=(y[i-1]+qpow(i,k-2))%mod;
        for(int i=1;i<=k;i++) fac[i]=1ll*fac[i-1]*i%mod,ifac[i]=qpow(fac[i],mod-2);
        pre[0]=1;for(int i=1;i<=k;i++) pre[i]=1ll*pre[i-1]*(n-i)%mod;
        suf[k+1]=1;for(int i=k;i;i--) suf[i]=1ll*suf[i+1]*(n-i)%mod;
        int res=0;
        for(int i=1;i<=k;i++) res=(res+1ll*(((k-i)&1)?-1:1)*y[i]*pre[i-1]%mod*suf[i+1]%mod*ifac[i-1]%mod*ifac[k-i]%mod)%mod;   
        return (res+mod)%mod;
    }
    
    int A,n;
    
    int main() {
        read(A),read(n),read(mod);
        for(int i=0;i<=n;i++) g[i]=((i&1)?1:-1)*power_sum(A,i);
        f[0]=1;int t=1;
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=i;j++)
                f[i]=(f[i]+1ll*g[j]*f[i-j])%mod;
            f[i]=1ll*f[i]*qpow(i,mod-2)%mod;
            t=1ll*t*i%mod;
        }
        write((1ll*f[n]*t%mod+mod)%mod);
        return 0;
    }
    
  • 相关阅读:
    IntelliJ IDEA使用心得之问题篇;
    IntelliJ IDEA使用心得之Maven项目篇
    IntelliJ IDEA使用心得之非Maven项目篇
    IntelliJ IDEA使用心得之插件篇
    IntelliJ IDEA使用心得之快捷键篇
    新博客地址
    【转载】Dijkstra算法和Floyd算法的正确性证明
    【转载】最小生成树之Kruskal算法
    论自动AC机
    【转载】C++ STL priority_queue用法
  • 原文地址:https://www.cnblogs.com/hbyer/p/10890702.html
Copyright © 2011-2022 走看看