0
点赞
收藏
分享

微信扫一扫

C. Two Arrays(组合数学/动态规划) Educational Codeforces Round 80 (Rated for Div. 2)

原题链接: ​​https://codeforces.com/problemset/problem/1288/C​​

C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_ios
测试样例

Input
2 2
Output
5
Input
10 1
Output
55
Input
723 9
Output
157557417

Note

In the first test there are 5 suitable arrays:

  • a=[1,1],b=[2,2];
  • a=[1,2],b=[2,2];
  • a=[2,2],b=[2,2];
  • a=[1,1],b=[2,1];
  • a=[1,1],b=[1,1].


题意: 给定一个整数C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_数组_02C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_动态规划_03,你需要构造两个数组C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_数组_04C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_ios_05,其中C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_数组_04C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_ios_05的元素都要从C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_#define_08中选取(可以重复选取构造。),你需要使得构造后的数组满足以下条件:

  • C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_#define_09
  • 数组C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_动态规划_10是非递减序列。
  • 数组C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_ios_11是非递增序列。

请你找出多少中构造数组C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_数组_04C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_ios_05的方法来达到条件。

解题思路: 待会我会介绍去两种解法,在这之前我们先来说一下共同点 。数组C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_数组_04非递减的,我们反转C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_ios_05,是不是反转后的C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_ios_05也是非递减的,那么此时C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_数组_04C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_ios_05假设我们都可以达成条件(这两个是不互相关联的,自然容易)。那么关键条件就是在于C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_#define_09,反转后我们C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_#define_20,则按要求得知,C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_#define_21。这时候我们则可以做一个操作,即将数组C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_动态规划_10和反转后的数组C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_ios_11拼接起来,那么所有的条件都会满足,即我们这个题目相当于在构建长度为C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_算法_24非递减数组。 这是这道题的关键,如果知道这个下面这两种方法相信你也很快可以知道。

  • 解法一:组合数学(非常灵活巧妙)
    我们知道,我们的取值为C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_数组_25,那么我们需要构造C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_算法_24个数,我们可以理解为往这C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_ios_27个“盒子“里填数,为了计算方便,我们可以假定盒子里原来就有属于自己的标号数。那么假设我们是按照规则来填的,也就是说我们已经填好了,其中有C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_#define_28个缝,那么我们只要从中选取C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_算法_24个缝进行切割即可选取到C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_算法_24个数,所以这就是一个组合问题。这里还需要注意的细节就是我们运算会出现除法,而我们是要求余,这自然行不通。所以我们要利用费马小定理来进行转换,若你不是很懂,则可以看一下这篇blog:​​​【费马小定理】​​
  • 解法二:动态规划
    动态规划怎么解决这道题呢?同样是构建,我们只不过是利用动态规划的思想来解决这些题。OK,我们寻找状态,我们是要构建C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_算法_24的非递减数组,找到构建这种数组的方法数量,那么我们则可以定义这样一个状态我们设:C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_ios_32表示为当构建数组长度为C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_动态规划_33时结尾数字为C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_动态规划_34的方法数量。确定了这个,我们来寻找状态转移方程。前面的状态即为数组长度为C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_算法_35,我们做状态转移时千万不要跨界,要一步一步转移,C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_ios_32的上一个状态即为C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_动态规划_37,当然,可不止这个,还有C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_数组_38,那么状态转移方程自然可以写出:
    C. Two Arrays(组合数学/动态规划)  Educational Codeforces Round 80 (Rated for Div. 2)_#define_39
    知道这个,自然易解。
    组合数学AC代码
/*

*
*/
#include<bits/stdc++.h> //POJ不支持

#define rep(i,a,n) for (int i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (int i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pair

using namespace std;

const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 1e4+2;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//


int n,m;
ll dp[maxn];
const ll mod=1e9+7;//为质数。
void init(){
dp[0]=dp[1]=1;
rep(i,2,maxn){
dp[i]=dp[i-1]*i%mod;//计算阶乘,打表。
}
}
ll feima(ll a,ll p){
//求解a^p次方,利用快速幂。
ll ans=1;
while(p){
if(p&1){
//说明b是奇数,我们得先提取使得变为偶数。
ans=ans*a%mod;
}
a=a*a%mod;
p>>=1;//左移,相当于除以2.
}
return ans;
}
void solve(ll a,ll b){
ll ans;
if(b>a||b<0)
cout<<0<<endl;
else{
ans=dp[a]*feima(dp[b]*dp[a-b]%mod,mod-2)%mod;
cout<<ans<<endl;
}
}
int main(){
//freopen("in.txt", "r", stdin);//提交的时候要注释掉
IOS;
init();
while(cin>>n>>m){
solve(2*m+n-1,n-1);
}
return 0;
}

动态规划AC代码

/*

*
*/
#include<bits/stdc++.h> //POJ不支持

#define rep(i,a,n) for (int i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (int i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pair

using namespace std;

const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 1e3+5;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//

int n,m;
ll dp[24][maxn];
const ll mod = 1e9+7;
void solve(int n,int m){
memset(dp,0,sizeof(dp));
rep(i,1,n){
//长度为1时,构造方法自然为1中。
dp[1][i]=1;
}
m<<=1;
rep(i,2,m){
rep(j,1,n){
dp[i][j]=(dp[i][j-1]+dp[i-1][j])%mod;
}
}
//每种数组结尾的方法都具有,故我们要统计之和。
ll ans=0;
rep(i,1,n){
ans+=dp[m][i];
ans%=mod;
}
cout<<ans<<endl;
}
int main(){
//freopen("in.txt", "r", stdin);//提交的时候要注释掉
IOS;
while(cin>>n>>m){
solve(n,m);
}
return 0;
}


举报

相关推荐

0 条评论