2019 ICPC 南京 Regional I. Space Station(DP && 哈希)

题意:

n n n个数字 a 1 , 2 , . . n a_{1,2,..n} a1,2,..n,你的初始能量为 a 0 a_0 a0,每次只能选取小于等于当前能量的数字,选完数字 a i a_i ai后当前能量会加上 a i a_i ai,求选完所有数字的方案数 m o d   1 e 9 + 7 mod\ 1e9+7 mod 1e9+7
n ≤ 1 e 5 , 0 ≤ a i ≤ 50 n\le1e5,0\le a_i\le 50 n1e5,0ai50

解题思路:

注意到 a i a_i ai很小,当前能量超过 a i a_i ai的上限之后就可以随意选取了。所以我们可以考虑直接记忆化搜索,注意把0单独拎出来。
搜 索 结 点 数 目 = 50 的 划 分 数 = 204226 搜索结点数目=50的划分数=204226 =50=204226
当前搜索的状态可以哈希之后存到unorder_map里面,也可以自己写个哈希去存,直接map结构体会超时,map哈希值也会超时。
复杂度 O ( f ( 50 ) ∗ 50 ∗ 映 射 函 数 平 均 查 找 时 间 ) O(f(50)*50*映射函数平均查找时间) O(f(50)50)
ac代码:

#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define ull unsigned long long
using namespace std;
const int mod = 1e9 + 7;
struct node{
    
    
    int a[51];
    node(){
    
    memset(a,0,sizeof a);}
};
const int maxn = 1e5 + 50;
int fac[maxn], ifac[maxn];
int qm(int a, int b){
    
    
    int res = 1;
    while(b){
    
    
        if(b&1) res = (ll)res*a%mod;
        a = (ll)a*a%mod;
        b >>= 1;
    }return res;
}
int n;
unordered_map<ull,int> mp;
ull sed = 131;
ull p[55];
node state;
int dp(int cur, int res){
    
    
    if(res == 0) return 1;
    if(cur >= 50){
    
    
        return fac[res];
    }
    ull ha = 0;
    for(int i = 50; i > 0; --i) ha = ha*sed+state.a[i];
    if(mp.find(ha) != mp.end()) return mp[ha];
    int ans = 0;
    for(int i = 1; i <= cur; ++i){
    
    
        if(!state.a[i]) continue;
        int t = state.a[i];
        --state.a[i];
        ans = (ans+(ll)t*dp(cur+i, res-1)%mod)%mod;
        ++state.a[i];
    }
    mp[ha] = ans;
    return ans;
}
int main()
{
    
    
    p[0] = 1; for(int i = 1; i < 55; ++i) p[i] = p[i-1]*sed;
    fac[0] = ifac[0] = 1;
    for(int i = 1; i < maxn; ++i) fac[i] = (ll)fac[i-1]*i%mod;
    ifac[maxn-1] = qm(fac[maxn-1], mod-2);
    for(int i = maxn-2; i > 0; --i) ifac[i] = (ll)ifac[i+1]*(i+1)%mod;
    scanf("%d", &n);
    int cur, num = 0, z = 0; scanf("%d", &cur);
    for(int i = 1; i <= n; ++i){
    
    
        int x; scanf("%d", &x);
        if(x == 0) z++;
        else state.a[x]++, num++;
    }
    int ans = dp(cur, num);
    ans = (ll)ans * (ll)fac[n]%mod*(ll)ifac[n-z]%mod;
    cout<<ans<<endl;
}

猜你喜欢

转载自blog.csdn.net/qq_43202683/article/details/104099322