组合数学做法(60'超时)

\(x_0+x_1+x_2+x_3 = n, x_0 \ge 1, x_1 \ge 1, x_2 \ge 1, x_3\ge 1\)
这样枚举答案的时间复杂度是\(O(n^3)\)
\(x_2 == 1\)时:
直接给出结果。
\(x_2 \ge 2\)时:
\(ans = \sum_{i=2}^{x_0+x1+1} C_{i+x2-2-1}^{i-1}*C_{(x_0+x1+2-i)+x3-1}^{(x_0+x_1+2-i)-1}\)
这里面的思路类比:
m个球放到n个盒子里面,盒子是可区别的。放2号球和放3号球是两个部分来做的。
我当时把它当成盒子不可区分的来做,套分拆数,结果就错了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 1000+10;
const int mod = 1e9+7;
int x0, x1, x2, x3;
ll ans = 0;
int n;
ll dp[maxn][maxn];

void init(){
    dp[0][0] = 0;
    for(int i=1; i<maxn; i++) dp[i][0] = 1, dp[i][1] = i;
    for(int i=2; i<=1000; i++){
        for(int j=1; j<=i;j++){
            dp[i][j] = (dp[i-1][j]+dp[i-1][j-1])%mod;
        }
    }
}


ll solve(){
    int tot = x0+x1;
    if(x2 == 1){
        return dp[tot+1+x3-1][x0+x1+1-1]%mod;
    }
    ll ans = dp[x0+x1+1+x3-1][x0+x1];
    for(int i=2; i<=x0+x1+1; i++){
        ans = (ans+dp[i+x2-2-1][i-1]*dp[(tot+2-i)+x3-1][(tot+2-i)-1]%mod)%mod;
    }
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
    init();
    cin>>n;
    ll temp;
    for(x0=1; x0<=n-3; x0++){
        for(x1=1; x1<=n-x0-2; x1++){
            for(x2 = 1; x2<=n-x0-x1-1; x2++){
                x3 = n-x0-x1-x2;
                if(x3==0) continue;
                temp = solve();
                ans = (ans+temp)%mod;
            }
        }
    }
    cout<<ans<<"\n";
    return 0;
}

超时了,乖乖看题解。。。

01-17 20:38