转载请注明出处,谢谢http://blog.csdn.net/acm_cxlove/article/details/7854526 by---cxlove
再一次在DIV1中怒跪~~~果断应该回到DIV2历练历练
A. Bracket Sequence
找出一个子串,而且它的括号匹配是规范的,要求里面的"[]"对数最多,输出任意一解
其实嘛,括号匹配就是一个堆栈模拟,可以想着想着就觉得有好多细节需要考虑,一直不想写
到了最后才写了枚举+栈模拟的,噗。。。结果必要没过嘛
其实没有那么复杂,记录从头到当前位置的[]个数,而且记录堆栈内每一个字符在串中的位置
当出现括号匹配,也就是弹出堆栈的时候就更新一下,注意堆栈为空的情况
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#include<set>
#define inf 110000000
#define M 10005
#define N 100005
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
using namespace std;
char str[N];
int sum[N];
int main(){
while(scanf("%s",str)!=EOF){
stack<int>s;
int l=strlen(str);
int ans=0,x,y;
sum[0]=(str[0]=='[');s.push(0);
for(int i=1;i<l;i++){
sum[i]=sum[i-1]+(str[i]=='[');
if(!s.empty()){
char ch=str[s.top()];
if((ch=='('&&str[i]==')')||(ch=='['&&str[i]==']')){
s.pop();
if(s.empty()&&sum[i]>ans){
ans=sum[i];
x=0;y=i;
}
else if(!s.empty()&&ans<sum[i]-sum[s.top()]){
ans=sum[i]-sum[s.top()];
x=s.top()+1;
y=i;
}
}
else s.push(i);
}
else s.push(i);
}
printf("%d\n",ans);
if(ans){
for(int i=x;i<=y;i++)
printf("%c",str[i]);
puts("");
}
}
return 0;
}
B. Two Strings
给出两个串a,b。问a中的每一个字符是否都出现在a的与b相同的子串中。
哎,被詹姐教育了番。。。
计算第一个字符,向前向后能匹配到的最远位置,看看之和是否大于模式串的长度
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#include<set>
#define inf 110000000
#define M 10005
#define N 200005
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define MOD 1000000007
using namespace std;
int front[N],back[N];
char a[N],b[N];
int pos[200];
int main(){
while(scanf("%s%s",a+1,b+1)!=EOF){
int l1=strlen(a+1),l2=strlen(b+1);
mem(pos,0);
int j=1;
for(int i=1;i<=l1;i++){
if(j<=l2&&a[i]==b[j]){
pos[a[i]]=j;
j++;
}
front[i]=pos[a[i]];
}
mem(pos,0);
j=l2;
for(int i=l1;i>0;i--){
if(j>0&&a[i]==b[j]){
pos[a[i]]=l2-j+1;
j--;
}
back[i]=pos[a[i]];
}
bool flag=true;
for(int i=1;i<=l1&&flag;i++)
if(front[i]+back[i]<=l2)
flag=false;
puts(flag?"Yes":"No");
}
return 0;
}
C. Partial Sums
给出一个序列,用这个序列的前i项和替换原来的序列,执行K次,输出最后的结果
其实可以YY出一个序列,表示当前这个数,是由多少个ai组成的。
比如当N=4,K=4的时候
1
4 1
10 4 1
20 10 4 1
只需要得到这个矩阵就可以了,可以发现是一个组合数C(i+k,i)
比如20=C(6,3) 10=C(5,2) 4=C(4,1) 1=C(3,0)
但是我当时傻叉地把组合数搞错了,我连C(N,M)=C(N,N-M)都没反应过来
哭瞎~~~~这里可以先预处理好这些组合数,组合数就暴力求就行了, 不过需要逆元
又学到了新的姿势,不过2000个数,可以直接快速幂来求
inv[i]表示i对于MOD的逆元
则 inv[i]=(-MOD/i*inv[MOD%i]); 这样通过递推O(1)就能求出每一个的逆元
从zhou神那得到了证明,其实就是证明这个的正确性
两边同时乘以i
inv[i]*i=i*(-MOD/i*inv[MOD%i]); (由逆元性质我们知道,a*inv[a]%MOD=1)
i*(-MOD/i) == (MOD%i)%MOD
-(MOD-MOD%i) == (MOD%i)%MOD
这是显然成立的,得证
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#include<set>
#define inf 110000000
#define M 10005
#define N 2005
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define MOD 1000000007
using namespace std;
LL inv[N],c[N],a[N];
LL slove(int n,int m){
LL ans=1;
for(int i=1;i<=m;i++)
ans=((ans*inv[i])%MOD*(n-i+1))%MOD;
return ans;
}
int main(){
int n,k;
while(scanf("%d%d",&n,&k)!=EOF){
for(int i=0;i<n;i++)
scanf("%I64d",&a[i]);
if(k==0){
for(int i=0;i<n;i++) printf("%I64d ",a[i]);
printf("\n");continue;
}
inv[0]=inv[1]=1;
for(int i=2;i<N;i++)
inv[i]=((-MOD/i*inv[MOD%i])%MOD+MOD)%MOD;
for(int i=0;i<n;i++)
c[i]=slove(i+k-1,i);
for(int i=0;i<n;i++){
LL ans=0;
for(int j=0;j<=i;j++)
ans=(ans+a[j]*c[i-j])%MOD;
printf("%I64d ",ans);
}
puts("");
}
return 0;
}