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;
}
字符串