Attack on Titans
题意:有三种兵A,B,C,选n个排队,问(至少m个连续的B和至多k个连续的C)的方案数。
理解了很长时间,,,好菜=_=||
先贴上代码,有空来写
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int maxn = 1000010; 5 const int mod = 1000000007; 6 ll d[maxn][4]; 7 ll n,m,k; 8 ll cal(int u){ 9 d[0][0]=1; 10 d[0][1]=0; 11 d[0][2]=0; 12 for(int i=1;i<=n;i++){ 13 ll sum=(d[i-1][0]+d[i-1][1]+d[i-1][2])%mod; 14 d[i][2]=sum; 15 16 if(i<=u) d[i][0]=sum; 17 else if(i==u+1) d[i][0]=(sum-1)%mod; 18 else d[i][0]=(sum-d[i-u-1][1]-d[i-u-1][2])%mod; 19 20 if(i<=k) d[i][1]=sum; 21 else if(i==k+1) d[i][1]=(sum-1)%mod; 22 else d[i][1]=(sum-d[i-1-k][0]-d[i-1-k][2])%mod; 23 } 24 return (d[n][0]+d[n][1]+d[n][2])%mod; 25 } 26 int main(){ 27 while(scanf("%d%d%d",&n,&m,&k)!=EOF){ 28 ll ans=cal(n); 29 ans=((ans-cal(m-1))%mod+mod)%mod; 30 printf("%lld ",ans); 31 } 32 return 0; 33 }
Mex
题意:求所有区间的mex和。mex值为没有在该区间出现过的最小非负整数。
感谢大神的分析http://blog.csdn.net/cc_again/article/details/11856847,可是对我等蒟蒻还是难以理解~~
又想了很久才有点明白orz▄█▀█●,模拟一波~
我们求以i结尾的区间的mex和f[i],再累加就是答案。为什么要这样求呢?因为可以从f[i-1]推出f[i]。记f[i] = f[i-1] +temp 。
初始temp=0,下面求temp。
现在看求第f[i]的过程,现在数列中加入了新的数val=a[i]
首先可以想到的是,对于上一个出现val的位置p(即代码里的last[a[i]]),p之前的元素(即f[p-1],f[p-2],…… f[1])对f[i]的结果没有任何影响(因为在a[i]之前的区间里已经有val了)
现在考虑p到i之间的元素,可以知道,他们中可能有 因为没有val这个元素 而导致 到f[i-1]的mex是比小于等于val的,而现在加入了val,那么它的mex就会增大
那么加入val之后都对哪些元素有影响呢?
这里定义一个覆盖:如果j到i之间出现了0到x的所有值,那么称x的 覆盖为j。
对于新加入的val,求出val-1的覆盖j,那么对于p(上一个val的位置)+1到 min ( j , last[val] )之间的元素,他们到a[i]=val这个位置的mex都【至少】是val+1,本来他们到a[i-1]的mex是val,即都变大了1。此时temp += min ( j , last[val] ) - p。
上面为什么说至少呢?说明还有可能大于val+1。
举个例子,6 4 0 2 1 5 3 。现在处理第七位3, f[7] = f[6] + temp = 9 + temp 。
加入3之后,根据上面的步骤,我们先求得2的覆盖是3,所以1到3的mex至少变成了4(他们在加入3之前是3),但是显然6的mex是7,4的mex是6,这一步只使得a[3]的mex值正确了。 此时temp +=3。 temp=3。
这是因为前面已经出现了4,5,6,在加入3之前他们没有任何,加入3导致他们也有了作用。这就等价于我们又加入了4,5,6
所以我们还要求3的覆盖,4的覆盖,5的覆盖……,直到mex值完全正确。
步骤如下:
加入4,last[4]=2,3的覆盖是3,所以1到2 ( min(3,last[4] ) 的mex变成了5, 此时temp +=2。 temp=5。
继续,加入5,last[5]=6,4的覆盖是2,所以1到2 ( min(2,last[5] ) 的mex变成了6, 此时temp +=2。 temp=7。
继续,加入6,last[6]=1,5的覆盖是1,所以1到1 ( min(2,last[5] ) 的mex变成了7, 此时temp +=1。 temp=8。
到此就结束了。
所以f[i] = f[i-1] +temp = 9 + 8 =17 。
下面代码里的mp就是上面分析中说到的覆盖。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 int a[200002],last[200002],mp[200002]; 5 int main() 6 { 7 int n,cnt; 8 while(scanf("%d",&n)&&n){ 9 for(int i=1;i<=n;i++) 10 scanf("%d",&a[i]); 11 12 ll ans=0; 13 ll temp=0,pre; 14 memset(last,0,sizeof(last)); 15 memset(mp,0,sizeof(mp)); 16 for(int i=1;i<=n;i++){ 17 if(a[i]<=n){ //如果大于n,不会影响任何元素,mex的和不变 18 pre=last[a[i]]; 19 last[a[i]]=i; 20 for(int j=a[i];j<=n;j++){ 21 if(j) mp[j]=min(mp[j-1],last[j]); 22 else mp[j]=last[j]; 23 if(mp[j]>pre){ 24 temp+=mp[j]-pre; 25 }else break; 26 } 27 } 28 ans+=temp; 29 } 30 printf("%I64d ",ans); 31 } 32 return 0; 33 }
The King’s Ups and Downs
题意:给n个人(身高为1到n)排队,问高矮相间的排队方式有几种。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int maxn=22; 5 ll c[maxn][maxn]; 6 ll dp[maxn][maxn]; 7 ll ans[maxn]; 8 int n; 9 void init(){ 10 c[1][0]=c[1][1]=1; 11 for(int i=2;i<maxn;i++){ 12 c[i][0]=1; 13 for(int j=1;j<=i;j++) 14 c[i][j]=c[i-1][j-1]+c[i-1][j]; 15 } 16 } 17 int main(){ 18 init(); 19 dp[0][0]=dp[0][1]=1; 20 dp[1][0]=dp[1][1]=1; 21 ans[1]=1; 22 for(int i=2;i<=20;i++){ 23 ans[i]=0; 24 for(int j=1;j<=i;j++){ 25 ans[i]+=(dp[j-1][0]*dp[i-j][1]*c[i-1][j-1]); 26 } 27 dp[i][0]=dp[i][1]=ans[i]>>1; 28 } 29 int t; 30 scanf("%d",&t); 31 while(t--){ 32 int i,k; 33 scanf("%d%d",&i,&k); 34 printf("%d %lld ",i,ans[k]); 35 } 36 }
Number String
题意:让你求满足字符串s的n排列有多少种。要求,如果s[i]为D,那么第i位小于第i-1位,如果s[i]为I,那么第i位大于第i-1位,s[i]为?时无所谓。
用dp[i][j]表示第i为排小于等于j的方案数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int mod=1000000007; 4 const int maxn=1010; 5 char s[maxn]; 6 int dp[maxn][maxn]; 7 8 int main(){ 9 while(scanf("%s",s+2)!=EOF){ 10 memset(dp,0,sizeof(dp)); 11 int n=strlen(s+2)+1; 12 dp[1][1]=1; 13 for(int i=2;i<=n;i++){ 14 for(int j=1;j<=i;j++){ 15 dp[i][j]=dp[i][j-1]; 16 if(s[i]=='D'||s[i]=='?') dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod; 17 if(s[i]=='I'||s[i]=='?') dp[i][j]=((dp[i][j]+(dp[i-1][i-1]-dp[i-1][j-1]))%mod+mod)%mod; 18 } 19 } 20 printf("%d ",dp[n][n]); 21 } 22 return 0; 23 }