Codeforces #247 (Div. 2) C. k-Tree

题意就不说了

我上来就用暴力回溯写了,这几天练暴力练得脑残了尴尬

暴力的代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
#define MAXN 10010
#define ll long long
using namespace std;

int n, k, d;
int maxs, sum;
int a[MAXN];
ll tot;

void search(int cur) {
    if(sum >= n) {
        if(sum == n) {
            for(int i=0; i<cur; ++i)
                maxs = max(maxs, a[i]);
//            cout << "maxs = " << maxs << endl;
            if(maxs>=d && maxs <=k) {
                tot++;
                /*
                for(int i=0; i<cur; ++i) {
                    cout << a[i] << " ";
                }
                cout << endl;
                */
            }
        }
        maxs = -1;
    }
    else {
        for(int i=1; i<=n; ++i) {
            a[cur] = i;
            maxs = max(maxs, i);
            sum += i;
            search(cur+1);
            sum -= i;
        }
    }
}

int main(void) {
    while(cin >> n >> k >> d) {
        sum = 0;
        tot = 0;
        maxs = -1;
        search(0);
        cout << tot%(1000000007) << endl;
    }
    return 0;
}

第5个样例就TLE了

今天看别人的代码才看懂

用递推做的

先找到所有和为n,n拆分后的加数最大项小于等于k的情况总个数ans1

然后找到所有和为n, n拆分后的加数最大项小于d的情况总个数ans2

然后输出((ans1-ans2)%(1e9+7)+(1e9+7))%(1e9+7)

代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXN 110
#define ll long long
#define MASK 1000000007
using namespace std;

ll f1[MAXN][MAXN];
ll f2[MAXN][MAXN];

int main(void) {
    int n, k, d;
//    f[i][j]表示把和为j的数拆分成i项有多少种情况
    while(cin >> n >> k >> d) {
        memset(f1, 0, sizeof(f1));
        for(int i=1; i<=k; ++i) {
            f1[1][i] = 1;
        }
        for(int i=2; i<=n; ++i) {
            for(int j=2; j<=n; ++j) {
                int t = min(j, k);
                for(int l=1; l<=t; ++l) {
                    f1[i][j] = (f1[i][j]+f1[i-1][j-l])%MASK;
                }
            }
        }

        memset(f2, 0, sizeof(f2));
        for(int i=1; i<d; ++i)
            f2[1][i] = 1;
        for(int i=2; i<=n; ++i) {
            for(int j=2; j<=n; ++j) {
                int t = min(j, d-1);
                for(int l=1; l<=t; ++l) {
                    f2[i][j] = (f2[i][j]+f2[i-1][j-l])%MASK;
                }
            }
        }
        ll ans = 0;
        for(int i=1; i<=n; ++i) {
            ans += f1[i][n];
        //    cout << "f1[" << i << "][" << n << "] = " << f1[i][n] << endl;
        }
        for(int i=1; i<=n; ++i) {
            ans -= f2[i][n];
        //    cout << "f2[" << i << "][" << n << "] = " << f2[i][n] << endl;
        }
        cout << (ans%MASK+MASK)%MASK << endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值