CodeForces - 466D Increase Sequence(思维,讨论)

题目链接:点击这里

题目大意:
给定一个长为 n n n 的序列 a i a_i ai ,然后给定一个正整数 k k k ,每次可以选择一个之前没选过的区间 [ l , r ] [l,r] [l,r] ,使得 a i , i ∈ [ l , r ] a_i,i\in [l,r] ai,i[l,r] 1 1 1 ,问有多少种方案可以使序列的所有元素都等于 k k k

题目分析:
因为需要让所有数都变成 k k k ,所以可以先对序列做变换: a i = k − a i a_i=k-a_i ai=kai
此时问题转化为每次操作选一个区间使之减一,最终元素全变为 0 0 0
然后考虑相邻两项的差值 d = a i − a i − 1 d=a_i-a_{i-1} d=aiai1
d p [ i ] dp[i] dp[i] 为把 a 1 a_1 a1 a i a_i ai 都变为 0 0 0 的最小操作次数
∣ d ∣ > 1 |d|>1 d>1 显然无解,因为每个区间只能选一次
d = 0 d=0 d=0 我们就可以从 d p [ i − 1 ] dp[i-1] dp[i1] 转移过来,对于当前元素可以选择用之前的操作归零或者新开一段,继承是 a [ i ] a[i] a[i] ,终止上一段区间新开一个是 1 1 1 ,所以此时 d p [ i ] = d p [ i − 1 ] ∗ ( a [ i ] + 1 ) dp[i]=dp[i-1]*(a[i]+1) dp[i]=dp[i1](a[i]+1)
d = − 1 d=-1 d=1 表示一定要终止当前区间了,所以需要乘上 C a i − 1 1 = a i − 1 C_{a_{i-1}}^1=a_{i-1} Cai11=ai1
d = 1 d=1 d=1 表示一定要开一段新的区间,所以继承 d p i − 1 dp_{i-1} dpi1 即可

具体细节见代码:

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#define ll long long
#define inf 0x3f3f3f3f
#define int  ll
#define endl '\n'
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
using namespace std;
int read()
{
	int res = 0,flag = 1;
	char ch = getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch == '-') flag = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
	{
		res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
		ch = getchar();
	}
	return res*flag;
}
const int maxn = 5e3+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
int n,m,k,a[maxn],sum[maxn],dp[maxn];
bool flag;
signed main() 
{
	n = read(),k = read();
	for(int i = 1;i <= n;i++) a[i] = read(),a[i] = k-a[i];
	dp[0] = 1;
	for(int i = 1;i <= n+1 && !flag;i++)
	{
		int d = a[i]-a[i-1];
		if(abs(d) >= 2) flag = true;
		if(d == 0) dp[i] = dp[i-1]*(a[i]+1)%mod;
		if(d == -1) dp[i] = dp[i-1]*a[i-1]%mod;
		if(d == 1) dp[i] = dp[i-1];
//		cout<<d<<" "<<dp[i]<<endl;
	}
	if(flag) puts("0");
	else cout<<dp[n+1]<<endl;
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值