CF1149B Three Religions(dp)
一道dp好题,初始的不含加减的根据数据范围,容易猜测出状态的设计,表示f[i][j][k],表示最近的匹配1的前i个,2的前j个,3的前k的答案
现在考虑更新,这里我们发现更新只有1e3,这是一个很奇怪的询问
我当时做到这里没有想到的是,因为你只添加一个串的后缀或减去,加入添加,就相当于多增加了250*250的状态,只要重新枚举更新即可
如果删除,直接就把长度--,这样最后一位带来的状态全部取消了,这里是思维转化的要点
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,ll> pll; const int N=1e5+10; const int inf=0x3f3f3f3f; const int mod=1e9+7; char s[5][300]; int len[5]; char p[N]; int n,q; int nxt[N][30]; int f[255][255][255]; void init(){ int i,j; for(i=0;i<26;i++){ nxt[n+1][i]=nxt[n+2][i]=n+1; } for(i=n;i>=1;i--){ for(j=0;j<26;j++){ if(p[i]==j+'a'){ nxt[i][j]=i; } else{ nxt[i][j]=nxt[i+1][j]; } } } } void solve(){ char c; int id; cin>>c>>id; int i,j,k; if(c=='+'){ char tmp; cin>>tmp; s[id][++len[id]]=tmp; for(i=(id==1?len[1]:0);i<=len[1];i++){ for(j=(id==2?len[2]:0);j<=len[2];j++){ for(k=(id==3?len[3]:0);k<=len[3];k++){ auto &x=f[i][j][k]; x=n+1; if(i) x=min(x,nxt[f[i-1][j][k]+1][s[1][i]-'a']); if(j) x=min(x,nxt[f[i][j-1][k]+1][s[2][j]-'a']); if(k) x=min(x,nxt[f[i][j][k-1]+1][s[3][k]-'a']); } } } } else{ len[id]--; } if(f[len[1]][len[2]][len[3]]<=n) cout<<"YES"<<endl; else cout<<"NO"<<endl; } int main(){ ios::sync_with_stdio(false); cin>>n>>q; cin>>(p+1); init(); while(q--){ solve(); } return 0; }
没有人不辛苦,只有人不喊疼