1 条题解
-
0
自动搬运
来自洛谷,原作者为

λᴉʍ
大家好,我是刚学OI的萌新搬运于
2025-08-24 22:08:14,当前版本为作者最后更新于2019-02-27 16:38:25,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
毒毒题,对着嘤文题解看了贼久
首先考虑此题的一个弱化版本:如果输入的所有相等怎么做
现在假设有个数,取值从到,而且每连续个数至少有一个是
那么取值就只有和两种取值了,的取值有种,设为
那么有一个显然的dp,表示这个问题i个数的答案
枚举这个数列的最后一个取值为的数,假设是第个,那么后面的个数有种选法
这个dp显然是不行的,还有一个dp,也是设表示这个问题i个数的答案
第个数随便选,乘个数的答案,这时可能出现问题,就是第个数到第个数都导致了不合法,所以要减掉这些情况
为什么减掉的是呢,显然这个数的放法共种没有问题,要注意一下从第个数到第个数都,那么只有第个数取值是才能够满足最小值的条件,所以前面的取值方案数是
il int solve(int v,int len){ int x=1000000000-v,xk=pow(x,k); f[0]=f[1]=1; for(int i=2;i<=len+1;++i){ f[i]=1ll*(x+1)*f[i-1]%mod; if(i-k-1>=0)f[i]=(f[i]-1ll*xk*f[i-k-1]%mod+mod)%mod; } return f[len+1]; }那么解决了前面的问题,后面的也很好办
设表示现在假设有个数,取值从到,而且每连续个数至少有一个是问题的答案,可以在时间内球解
首先,可以将一段相等的合并起来
然后(开始口胡)
对于一个段,如果只有这一段,方案数为
如果有一个
那么可以知道的是
这里可以推出
前面已经推出了,所以这些都不可能是最小值
这一段的最小值只能有一个就是
前面的数也都在前一段的范围内
所以这一段最前面个数就没了,其中前个数会在前面段计算答案,第个数只有一个取值
对于后面也同理,如果则后面个数没了
所以一段的len实际上是减去0到2个
对于所有的段依次球解最后方案数乘起来即可
代码极为简单
#include<bits/stdc++.h> #define il inline #define vd void #define mod 1000000007 typedef long long ll; il ll gi(){ ll x=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')f=-1; ch=getchar(); } while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } int n,k; int a[100010]; int f[100010]; il int pow(int x,int y){ int ret=1; while(y){ if(y&1)ret=1ll*ret*x%mod; x=1ll*x*x%mod;y>>=1; } return ret; } il int solve(int v,int len){ int x=1000000000-v,xk=pow(x,k); f[0]=f[1]=1; for(int i=2;i<=len+1;++i){ f[i]=1ll*(x+1)*f[i-1]%mod; if(i-k-1>=0)f[i]=(f[i]-1ll*xk*f[i-k-1]%mod+mod)%mod; } return f[len+1]; } int main(){ #ifndef ONLINE_JUDGE freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif n=gi(),k=gi(); for(int i=1;i<=n-k+1;++i)a[i]=gi(); int ans=1,len; for(int i=1,j;i<=n-k+1;i=j+1){ j=i; while(a[j+1]==a[i])++j; len=j-i+k; if(i!=1&&a[i-1]>a[i])len-=k; if(j!=n-k+1&&a[j+1]>a[i])len-=k; if(len>0)ans=1ll*ans*solve(a[i],len)%mod; } printf("%d\n",ans); return 0; }
- 1
信息
- ID
- 4173
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者