D
简单区间dp
一个合法的括号序列染色,一对匹配的括号必须有一个被染成红色或者蓝色,另一个不染色。
被染色的相邻括号不能相同颜色,问有几种染色的方法。
直接区间dp,转移就是考虑每种情况然后相乘就可以了。
#include<bits/stdc++.h>
#include<stack>
#define MOD 1000000007
using namespace std;
char s[1000];
int p[1000];
long long dp[3][3][705][705];
int main(){
cin>>s+1;
int len=strlen(s+1);
stack<int>stk;
for (int i=1;i<=len;i++){
if (s[i]=='(')stk.push(i);
else {
p[i]=stk.top();
p[stk.top()]=i;
stk.pop();
}
}
memset(dp,0,sizeof(dp));
for (int i=2;i<=len;i++){ //changdu
for (int l=1;l<=len-i+1;l++){ //weizhi
int m=p[l];
int r=l+i-1;
if (m>l&&m!=r){ //中间截断
for (int j=0;j<3;j++){
for (int k=0;k<3;k++){
for (int h=0;h<3;h++){
for (int g=0;g<3;g++){
if (h&&g&&g==h) continue;
dp[j][k][l][r]+=(dp[j][h][l][m]*dp[g][k][m+1][r]);
dp[j][k][l][r]%=MOD;
}
}
}
}
}
else if (m==r){
if (i==2){
dp[0][1][l][r]=dp[0][2][l][r]=dp[1][0][l][r]=dp[2][0][l][r]=1;
}
else{
for (int j=0;j<3;j++){
for (int k=0;k<3;k++){
if (j==0&&k==0||j&&k) continue;
for (int h=0;h<3;h++){
if (j&&h&&j==h) continue;
for (int g=0;g<3;g++){
if (k&&g&&k==g) continue;
dp[j][k][l][r]+=(dp[h][g][l+1][r-1]);
dp[j][k][l][r]%=MOD;
}
}
}
}
}
}
}
}
long long ans=0;
for (int i=0;i<3;i++){
for (int j=0;j<3;j++){
ans+=dp[i][j][1][len];
ans%=MOD;
}
}
cout<<ans<<endl;
}
E
后缀自动机
其实还是不太会这个东西,又看了一遍clj老师的讲稿,但是这题的应用确实还蛮基础的。
正反建两个后缀自动机,然后对于每个字符串匹配最优的情况就可以了。
#include<bits/stdc++.h>
#include<iostream>
#include<string.h>
#define N 100005
#define INF 0x3f3f3f3f
using namespace std;
char s[N];
char s1[1005];
int n;
char text[N];
struct state{
state *par, *go[26];
int val,fst; //val==maxlen fst==very left
bool f,vis; //is the added node
state(int _val) :
par(0), val(_val), fst(INF), f(0), vis(0){
memset(go,0,sizeof(go));
}
};
struct suffixautomaton{
state *root, *last;
void extend(int w){
state *p=last;
state *np=new state(p->val+1);
while (p&&p->go[w]==0){
p->go[w]=np;
p=p->par;
}
if (p==0) np->par=root;
else{
state *q=p->go[w];
if (p->val+1==q->val){
np->par=q;
}
else{
state *nq= new state(p->val+1);
memcpy(nq->go,q->go,sizeof(q->go));
nq->par=q->par;
q->par=nq;
np->par=nq;
while (p&&p->go[w]==q) {
p->go[w]=nq;
p=p->par;
}
}
}
last=np;
np->f=true;
}
void work(state* now, int dep){
if (now->vis) return;
for (int i=0;i<26;i++){
if (now->go[i]){
text[dep+1]='A'+i;
work(now->go[i],dep+1);
now->fst=min(now->fst, now->go[i]->fst -1);
}
}
if (now->f) now->fst=min(now->fst, now->val);
now->vis=true;
return;
}
void init(char *s){
root=last=new state(0);
int len=strlen(s+1);
for (int i=1;i<=len;i++){
extend(s[i]-'A');
}
//for (int i=0;i<26;i++) cout<<i<<" "<<root->go[i]<<endl;
work(root,0);
}
void match(char *s, int *res){
int len=strlen(s+1);
state* now=root;
for (int i=1;i<=len;i++){
if (now->go[ s[i]-'A']){
now=now->go[ s[i]-'A'];
res[i]=now->fst;
}
else{
for (int j=i;j<=len;j++) res[j]=INF;
break;
}
}
}
}A,B;
int a[1005],b[1005];
int main(){
scanf("%s",s+1);
A.init(s);
int len=strlen(s+1);
reverse(s+1,s+len+1);
B.init(s);
scanf("%d",&n);
int ans=0;
for (int i=1;i<=n;i++){
scanf("%s",s1+1);
int len1=strlen(s1+1);
if (len1==1) continue;
A.match(s1,a);
/*
for (int i=1;i<=len1;i++){
cout<<a[i]<<" ";
}
cout<<endl;
*/
reverse(s1+1,s1+len1+1);
B.match(s1,b);
/*
for (int i=1;i<=len1;i++){
cout<<b[i]<<" ";
}
cout<<endl;
*/
for (int i=1;i<=len1;i++){
if (a[i]+b[len1-i]<=len){
ans++;
break;
}
}
}
printf("%d",ans);
return 0;
}
字符串