codeforces 466d Increase Sequence
Peter has a sequence of integers a1, a2, ..., an. Peter wants all numbers in the sequence to equal h. He can perform the operation of "adding one on the segment [l, r]": add one to all elements of the sequence with indices from l to r (inclusive). At that, Peter never chooses any element as the beginning of the segment twice. Similarly, Peter never chooses any element as the end of the segment twice. In other words, for any two segments [l1, r1] and [l2, r2], where Peter added one, the following inequalities hold: l1 ≠ l2 and r1 ≠ r2.
How many distinct ways are there to make all numbers in the sequence equal h? Print this number of ways modulo 1000000007 (109 + 7). Two ways are considered distinct if one of them has a segment that isn't in the other way.
The first line contains two integers n, h (1 ≤ n, h ≤ 2000). The next line contains n integers a1, a2, ..., an (0 ≤ ai ≤ 2000).
Print a single integer — the answer to the problem modulo 1000000007 (109 + 7).
3 2
1 1 1
4
5 1
1 1 1 1 1
1
4 3
3 2 1 1
0
题意:给出一个序列,可以对其进行以下操作,取一段长度,从l到r,将其中的数全部加一。操作的次数不限,但对于两个操作,要求l1!=l2 && r1!=r2。求共有几种操作集合,使得整个序列的值最后都等于h。
思路:想了好久还是想不出来,最后看的题解。反着来做,先将所有a[i]=h-a[i]。当然,为了后面方便计算,我们将边界条件a[0]=0,a[n+1]=0。由于操作中的限制(l1!=l2 && r1!=r2),所以我们很容易得出有解的情况是当且仅当-1<=a[i]-a[i-1]<=1。我们用变量cnt记录当前有多少个左端点l没有和右端点r配对。下面分类讨论:
1,a[i]-a[i-1]==1,此时i点上必定有一个左端点,所以cnt++,i-1点上没有右端点,所以不对ans进行操作。
2,a[i]==a[i-1],此时有两种情况,要嘛i点没有左端点,i-1点没有右端点,要嘛i点有左端点,i-1点有右端点。此时,第一种情况是cnt=0,第二种情况时,cnt++,ans×=cnt,cnt--。所以两种情况都可以用ans×=(cnt+1)来表示。
3,a[i]-a[i-1]=-1,此时i点没有左端点,i-1点必定有右端点,此时ans×=cnt,cnt--;
细节:因为我们统计右端点的情况是统计前一个的,所以循环的时候必须做到n+1位。
下面是代码
/* * Author: Joshua * Created Time: 2014年09月19日 星期五 20时36分35秒 * File Name: d.cpp */ #include<cstdio> #include<iostream> using namespace std; #define maxn 2002 typedef long long LL; int a[maxn],b[maxn],n,h; void solve() { int x; for (int i=1;i<=n;++i) { scanf("%d",&x); a[i]=h-x; } a[0]=0;a[n+1]=0; for (int i=1;i<=n+1;++i) { b[i]=a[i]-a[i-1]; if (b[i]>1 || b[i]<-1) { printf("0\n"); return; } } LL ans=1; int mod = int (1e9+7),cnt=0; for (int i=1;i<=n+1;++i) { if (b[i]==1) { cnt++; continue; } if (b[i]==0) ans*=(cnt+1); else ans*=(cnt--); ans %=mod; } cout<<ans<<endl; } int main() { while (scanf("%d%d",&n,&h)>0) solve(); return 0; }
改进:我们知道,当a[i]-a[i-1]==1的时候,cnt++,当a[i]-a[i-1]==-1的时候,cnt--,那么我们是不是就可以用a[i]来表示cnt呢,答案是可以。这样可以进一步降低时间复杂度,代码也更短,下面是改进后的代码。
/* * Author: Joshua * Created Time: 2014年09月19日 星期五 20时36分35秒 * File Name: d.cpp */ #include<cstdio> #include<iostream> using namespace std; #define maxn 2002 typedef long long LL; int a[maxn],b[maxn],n,h; void solve() { int x; for (int i=1;i<=n;++i) { scanf("%d",&x); a[i]=h-x; } a[0]=0;a[n+1]=0; for (int i=1;i<=n+1;++i) { b[i]=a[i]-a[i-1]; if (b[i]>1 || b[i]<-1) { printf("0\n"); return; } } LL ans=1; int mod = int (1e9+7); for (int i=1;i<=n+1;++i) { if (b[i]==1) continue; if (b[i]==0) ans*=a[i]+1; else ans*=a[i-1]; ans %=mod; } cout<<ans<<endl; } int main() { while (scanf("%d%d",&n,&h)>0) solve(); return 0; }