hihocoder编程练习赛73 A 地铁站
1 /* 2 Source :hihocoder编程练习73 3 Problem :一个长度为n的串,由若干段1-a[i](假设有Y段)的序列组成,现在中间缺了K个数,问能够还原出来的方案数,需要保证还原出来的子串的个数最少,即最小Y 4 Solution :1.通过分析剩余的序列,我们可以知道原来最少的时候Y是多少,即看原来的序列有多少单调递增的子段。 5 2.进行有解的判断,假设已知序列段中每段的最大值是b[i] i=1..Y,如果sum(b[i]) > N,则说明无解,这是序列的长度一定已经超过n了。 6 3.方案数求解,假设每段序列的最大值为x[i],有sum(x[i])=n,且需要满足x[i]>=b[i],令y[i]=x[i]-b[i]>=0 7 问题就转化为求sum(y[i])=n-sum(b[i])的解的个数,这是个经典的问题,用隔板法方案数为C(R+Y-1,Y-1), R=n-sum(b[i]). 8 Date :2018-08-19-11.57 9 */ 10 11 #include <bits/stdc++.h> 12 using namespace std; 13 14 typedef long long LL; 15 const int MAXN = 100005; 16 const LL MOD7 = 1e9+7; 17 18 19 LL Pow(LL a, LL b) 20 { 21 LL res=1LL; 22 LL ans=a%MOD7; 23 while (b) 24 { 25 if (b&1) res=res*ans%MOD7; 26 ans=ans*ans%MOD7; 27 b>>=1; 28 } 29 return res; 30 } 31 32 int a[MAXN]; 33 int N, K, M; 34 int m; 35 LL R; 36 LL Y; 37 38 39 LL C(LL n, LL r) 40 { 41 LL ans=1LL; 42 for (int i=1;i<=r;++i) 43 { 44 ans = ans * (n-i+1) % MOD7; 45 ans = ans * Pow(i, MOD7-2) % MOD7; 46 } 47 return ans; 48 } 49 50 void work() 51 { 52 LL ans=1LL; 53 ans = C((LL)R+Y-1, (LL)min(Y-1, R)); 54 printf("%lld\n",ans); 55 } 56 57 int main() 58 { 59 #ifndef ONLINE_JUDGE 60 freopen("test.txt","r",stdin); 61 #endif // ONLINE_JUDGE 62 scanf("%d%d",&N,&K); 63 m=N-K; 64 for (int i=1;i<=m;++i) 65 { 66 scanf("%d",&a[i]); 67 } 68 a[m+1]=0; 69 R=N; 70 Y=0; 71 for (int i=1;i<=m;++i) 72 { 73 if (a[i]>=a[i+1]) 74 { 75 ++Y; 76 R-=a[i]; 77 } 78 } 79 if (R<0) 80 { 81 printf("No\n"); 82 return 0; 83 } 84 work(); 85 return 0; 86 }