1. 程式人生 > >[NOI.AC] count

[NOI.AC] count

getchar code main 如果 ans sign lse ++ ...

思路:
考慮組合數學。
當所求中沒有重復的時候,方案數就是\(C_{n + 1}^{k}\)
當有重復的時候...
設相等的數字之間的距離為\(len\)
當取0個數時,方案數就是\(C_{n - 1}^{k}\)
取1個數時,方案數大概是\(2 * C_{n - 1}^{k - 1}\) ,但是如果相同的數字之間那一段沒有取任何一個其他的數,那麽取任意一個相同的數都是等價的,所以要減去\(C_{n - len}^{i - 1}\)
取了兩個數,方案數就是\(C_{n - 1}^{k - 2}\)
考試炸了範圍...

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long
const int maxn = 200010;
const int mod = 1e9+7;
int n;
inline int pow_mod(int x,int y) {
    int res = 1;
    while(y) {
        if(y & 1) res = res * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return res % mod;
}
inline int read() {
    int q=0,f=1;char ch = getchar();
    while(!isdigit(ch)){
        if(ch==-'-')f=-1;ch=getchar();
    }
    while(isdigit(ch)){
        q=q*10+ch-'0';ch=getchar();
    }
    return q*f;
}
int fac[maxn];
int a[maxn];
int vis[maxn];
int ifac[maxn];
inline int C(int x,int y) {
    if(x < y) return 0;
    if(y < 0) return 0;
    return fac[x] * ifac[y] % mod * ifac[x - y] % mod;
}
int len;
int ans[maxn];
inline void pre () {
    fac[0] = 1;
    for(int i = 1;i <= n + 1; ++i) {
        fac[i] = fac[i - 1] * i % mod;
    }
    ifac[n + 1] = pow_mod(fac[n + 1],mod - 2);
    for(int i = n;i >= 0; --i) {
        ifac[i] = ifac[i + 1] * (i + 1) % mod;
    }
}
signed main () {
    n = read();
    for(int i = 1;i <= n + 1; ++i) {
        a[i] = read();
        if(vis[a[i]] == 0) {
            vis[a[i]] = i;
        }
        else len = i - vis[a[i]] + 1;
    }
    pre();
    for(int i = 1;i <= n + 1; ++i) {
        int res = C(n - 1,i);
        res = (res + 2 * C(n - 1,i - 1)) % mod;
        res = (res - C(n - len + 1,i - 1) + mod) % mod;
        res = (res + C(n - 1,i - 2)) % mod;
        ans[i] = res;
    }
    for(int i = 1;i <= n + 1; ++i)
        printf("%lld\n",ans[i]);
    return 0;

}

[NOI.AC] count