The Preliminary Contest for ICPC Asia Shanghai 2019

D:Counting Sequences I

题意:求元素为n个的子序列的个数满足\sum_{i=1}^{n}a_{i} = \prod_{i=1}^{n}a_{i}.

思路:因为n<=3000,可以分析出最多有11个非1元素,dfs枚举剪枝,当所有非1元素的乘积 f 和加和 s 满足f-s+cnt>3000时,递归结束。一个序列的贡献为\frac{n!}{a!b!..},(a, b, c为每种数的个数)

代码:

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5+5;
const LL mod = 1e9+7;

LL quick_pow(LL a, LL b){
    LL sum = 1;
    while(b){
        if(b&1) sum = sum*a % mod;
        a = a*a%mod; b >>= 1;
    }return sum;
}

LL fac[maxn], ifac[maxn];
int num[maxn];
LL compt(int n, int one){
    unordered_map<int, int>mp;
    for(int i=1; i<=n; i++) mp[num[i]] ++;
    LL ans = fac[n+one] * ifac[one]%mod;
    for(auto it : mp) ans = ans * ifac[it.second] % mod;
    return ans;
}
LL ans[maxn];
void dfs(int cnt=0, int f=1, int sum=0){
    ans[f-sum+cnt] = (ans[f-sum+cnt] + compt(cnt, f-sum))%mod;
    for(int i=max(2, num[cnt]); i<=3000; i++){
        if(f*i-(sum+i) > 3000-(cnt+1)) break;
        num[cnt+1] = i;
        dfs(cnt+1, f*i, sum+i);
    }
}
int main()
{
    //freopen("D:\\out.txt", "w", stdout);
    fac[1]=ifac[1]=1; for(int i=2; i<=3005; i++) fac[i] = fac[i-1]*i%mod, ifac[i] = quick_pow(fac[i], mod-2);
    dfs();
    int t, n;
    cin >> t;
    while(t--){
        cin >> n;
        cout << (n==2?1:ans[n]) << endl;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值