小智的糖果(Candy)51nod提高组试题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
⼩智的糖果(Candy)51nod提⾼组试题
题⽬描述
⼩智家⾥来了很多的朋友,总共有N个⼈,站成⼀排,分别编号为0到N-1,⼩智要给他们分糖果。
但是有的朋友有⼀些特殊的要求,有的⼈要求他左右的两个⼈(左边⼀个、右边⼀个,⼀共2个⼈)的糖果数都⽐他的多,有的⼈要求他左右的两个⼈的糖果数都⽐他的少。
同时⼩智希望给不同的⼈分到的糖果数不相同,并且每个⼈⾄少有⼀个糖果,同时⼩智希望分出的糖果个数尽可能的少,现在⼩智想知道有多少种分糖果的⽅法。
数据保证不会出现两个⼈的要求产⽣冲突的情况。
输⼊格式
第⼀⾏三个数N,M,K,分别表⽰⼈数,第⼀种要求的⼈的个数,K表⽰第⼆种要求的⼈的个数。
接下来M⾏,每⾏⼀个数x,表⽰位置x的⼈要求他左右两个⼈的糖果数都⽐他的多接下来K⾏,每⾏⼀个数y,表⽰位置y的⼈要求他左右两个⼈的糖果数都⽐他的少
输出格式
输出⼀个数表⽰⽅法数对 1000000007取模的结果。
这道题考虑Dp解法。
如何想到⽤DP解法?因为题⽬中要求我们最多有多少种⽅法,如果⼀个个枚举或者求出的话,就会让我们的时间复杂度分分钟上去。
因此这类题都是套路⼀般的DP。
⾸先,看到题⽬中有两种要求。
⼀种是让两边的⼩,⼀种是让两边的⼤。
这种要求有⼀点不好处理的就是,我们总是喜欢直接查看每⼀个点的情况,⽽不是查看其旁边的点情况,这样很不⽅便。
于是我们转换⼀下。
设flag i = 1时,表⽰第 i 个点⼩于前⼀个点。
同样的,当 flag i = 2时,表⽰第i个点⼤于前⼀个点。
当然,falg = 0时,表⽰⽆特殊关系。
然后,设置⼀个dp[i][j] 表⽰由前 i 个数组成的序列且第 i 位为 j 的合法情况数。
在规划的过程中,针对不同的 flag[i],对应不同的状态转移,这⾥涉及到⼀个最后⼀位数 j 插⼊序列的思维,可以看做把前边的每⼀种排列中⼤于等于 j 的数 ++,也就可以达到空出 j 这个数将其插⼊的效果。
在这⾥引⼊⼀个 sum[j],表⽰为前⼀轮状态下,最后⼀位⼩于等于 j 的情况的和。
也就是说,当规划到第 i 位时,sum[j]表⽰前 i - 1 位数组成的序列的合法情况的 dp[i - 1][j] 的前缀和。
到这⾥,这道题也就可以被我们AC了。
我们要求的和就是 sum[n].
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define N 100100
#define isdigit(c) ((c)>='0'&&(c)<='9')
const int mod = (int)1e9 + 7;
inline int read(){
int x = 0, s = 1;
char c = getchar();
while(!isdigit(c)){
if(c == '-')s = -1;
c = getchar();
}
while(isdigit(c)){
x = (x << 1) + (x << 3) + (c ^ '0');
c = getchar();
}
return x * s;
}
int flag[N], sum[N], dp[N];
int main(){
// freopen("candy.in","r",stdin);
// freopen("candy.out","w",stdout);
int n = read(), K = read(), M = read();
for(int i = 1;i <= K; i++){
int a = read();
flag[++a] = 1;
flag[a + 1] = 2;
}
for(int i = 1;i <= M; i++){
int a = read();
flag[++a] = 2;
flag[a + 1] = 1;
}
dp[1] = sum[1] = 1;
for(int i = 2;i <= n; i++){
for(int j = 1;j <= i; j++){
if(flag[i] == 0){
dp[j] = sum[i - 1] % mod;
}
else if(flag[i] == 1){
dp[j] = (sum[i - 1] - sum[j - 1] + mod) % mod; }
else{
dp[j] = sum[j - 1];
}
}
for(int j = 1;j <= i; j++){
sum[j] = (sum[j - 1] + dp[j]) % mod;
}
}
cout << sum[n] << endl;
return0;
}。