Codeforces 932.E Team Work

本文介绍了一种计算特定任务中团队各种可能组合的成本总和的方法。通过巧妙地转换数学表达式并利用动态规划技术,解决了这一难题。最终给出了实现这一算法的具体代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

E. Team Work
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You have a team of N people. For a particular task, you can pick any non-empty subset of people. The cost of having x people for the task is xk.

Output the sum of costs over all non-empty subsets of people.

Input

Only line of input contains two integers N (1 ≤ N ≤ 109) representing total number of people and k (1 ≤ k ≤ 5000).

Output

Output the sum of costs for all non empty subsets modulo 109 + 7.

Examples
input
1 1
output
1
input
3 2
output
24
Note

In the first example, there is only one non-empty subset {1} with cost 11 = 1.

In the second example, there are seven non-empty subsets.

{1} with cost 12 = 1

{2} with cost 12 = 1

{1, 2} with cost 22 = 4

{3} with cost 12 = 1

{1, 3} with cost 22 = 4

{2, 3} with cost 22 = 4

{1, 2, 3} with cost 32 = 9

The total cost is 1 + 1 + 4 + 1 + 4 + 4 + 9 = 24.

题目大意:求.

分析:挺难的一道题,完全下不了手......

   官方题解给出的做法非常巧妙.首先这个式子一眼看上去肯定不能直接解.变换一下?不会. 可以想到一个比较相似的式子:.

   那么怎么把这个式子变成题目给的式子呢?找一找不同,要求的式子r是从1开始的,这个式子r是从0开始的; 要求的式子r作为底数,k作为幂次,而这个式子凭空出现了一个x.变换比较难想到:

可以把这个式子求个导,然后乘x. 

    求导可以将x的幂次中的r提出来一个,同时r=0时求导就变成了0.那么操作k次就能得到和要求的式子差不多的一个式子.有什么差别呢?式子中有x.

   消除掉x的影响就可以了,想办法令x的幂次为1.可以利用dp.设f[a][b][c]表示还剩a次操作,式子的值.如果b=0,c = n,同时令x = 1,那么这个式子操作k次后正好就是要求的式子.对这个式子操作一次,变成了:,那么可以得到递推式:f[a][b][c] = b * f[a - 1][b][c] + c * f[a - 1][b + 1][c - 1].,最后答案是f[k][0][n].

   看似是三次复杂度的dp,实际上是平方级别的,因为b和c的和一定等于n.那么dp只需要记录a和b的状态,c可以推出来. (不能记录c,因为c可能高达n,而实际上b和c最多只会变化k,b是从0开始的,所以记录b).

   代码中的a,b表示上述分析中的b,c,一定要考虑边界情况:b = 0或c = 0,当a = 0时,就是一些连续的组合数相加,因为中的x = 1,直接返回2^c.

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;

const ll mod = 1e9+7;

ll n,k,f[5010][5010];

ll qpow(ll a,ll b)
{
    ll res = 1;
    while (b)
    {
        if (b & 1)
            res = (res * a) % mod;
        a = (a * a) % mod;
        b >>= 1;
    }
    return res % mod;
}

ll dfs(ll dep,ll a)
{
    if (f[dep][a] >= 0)
        return f[dep][a];
    ll b = n - a;
    if (dep == 0)
        return f[dep][a] = qpow(2,b);
    return f[dep][a] = ((b?1LL*b*dfs(dep-1,a+1):0LL)+(a?1LL*a*dfs(dep-1,a):0LL))%mod;
}

int main()
{
    memset(f,-1,sizeof(f));
    cin >> n >> k;
    cout << dfs(k,0) % mod << endl;

    return 0;
}

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/zbtrs/p/8450198.html

### Codeforces Div.2 比赛难度介绍 Codeforces Div.2 比赛主要面向的是具有基础编程技能到中级水平的选手。这类比赛通常吸引了大量来自全球不同背景的参赛者,包括大学生、高中生以及一些专业人士。 #### 参加资格 为了参加 Div.2 比赛,选手的评级应不超过 2099 分[^1]。这意味着该级别的竞赛适合那些已经掌握了一定算法知识并能熟练运用至少一种编程语言的人群参挑战。 #### 题目设置 每场 Div.2 比赛一般会提供五至七道题目,在某些特殊情况下可能会更多或更少。这些题目按照预计解决难度递增排列: - **简单题(A, B 类型)**: 主要测试基本的数据结构操作和常见算法的应用能力;例如数组处理、字符串匹配等。 - **中等偏难题(C, D 类型)**: 开始涉及较为复杂的逻辑推理能力和特定领域内的高级技巧;比如图论中的最短路径计算或是动态规划入门应用实例。 - **高难度题(E及以上类型)**: 对于这些问题,则更加侧重考察深入理解复杂概念的能力,并能够灵活组合多种方法来解决问题;这往往需要较强的创造力丰富的实践经验支持。 对于新手来说,建议先专注于理解和练习前几类较容易的问题,随着经验积累和技术提升再逐步尝试更高层次的任务。 ```cpp // 示例代码展示如何判断一个数是否为偶数 #include <iostream> using namespace std; bool is_even(int num){ return num % 2 == 0; } int main(){ int number = 4; // 测试数据 if(is_even(number)){ cout << "The given number is even."; }else{ cout << "The given number is odd."; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值