成外NOIP2019模拟1
T1
大意:给你一个长度$\leq 300$的字符串,求出这个字符串所有子序列的价值和,一个串的价值为所有长度不大于$\frac{len+1}{2}$的$border$的长度之和
题解:
- 由于有了长度限制的条件,那么$border$的重叠位置只能最多为一,给人一种可以枚举其中的分界线的感觉,于是我们枚举$border$右边的第一个位置$p$
- 把串首串尾的$border$定好了之后中间取或不取随便,会乘上一个2的次幂
- 设$cnt_{i,j}$表示左边从1到$i$右边从$p$到$j$的两个串的公共子序列对数(对数不是个数,相同但是位置不同算多次),同理设$sum_{i,j}$表示的是...的所有对公共子序列的长度之和
- 考虑转移,若$s_i==s_j$,那么$sum_{i,j}=\sum_{k<i}\sum_{l<j}(sum_{k,l}+cnt_{k,l})$,因为之前所有的串都能长度加一,$cnt_{i,j}=\sum_{k<i}\sum_{l<j}cnt_{k,l}$
- 统计答案就是在$s_i==s_j$处,$ans+=sum_{i,j}*2^{\min\{0,p-i-1\}}$
- 然后前缀和优化一下就能$O(n^3)$
1 #include<bits/stdc++.h> 2 #define FOR(i,a,b) for (register ll i=(a);i<=(b);i++) 3 #define For(i,a,b) for (register ll i=(a);i>=(b);i--) 4 #define mem(i,j) memset(i,j,sizeof(i)) 5 #define GO(u) for (register ll j=f[u];j!=-1;j=nxt[j]) 6 #define fi first 7 #define se second 8 #define pb push_back 9 #define pii pair<ll,ll> 10 #define MP make_pair 11 using namespace std; 12 typedef long long ll; 13 const ll N=303; 14 const ll mod=998244353; 15 ll n,ans=0,nxt[N],er[N],cnt[N][N],sum[N][N]; 16 char s[N],b[N]; 17 inline ll read() 18 { 19 ll x=0,f=1; 20 char c=getchar(); 21 while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} 22 while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();} 23 return f*x; 24 } 25 inline void write(ll x) 26 { 27 if (x<0) putchar('-'),x=-x; 28 if (x>9) write(x/10); 29 putchar(x%10+'0'); 30 return; 31 } 32 inline void solve(int head) 33 { 34 FOR(i,1,n) FOR(j,1,n) sum[i][j]=cnt[i][j]=0; 35 FOR(i,1,head) 36 { 37 if (s[i]==s[head]) cnt[i][head]=sum[i][head]=1; 38 cnt[i][head]=(cnt[i][head]+cnt[i-1][head])%mod; 39 sum[i][head]=(sum[i][head]+sum[i-1][head])%mod; 40 } 41 FOR(i,1,head) FOR(j,head+1,n) 42 { 43 cnt[i][j]=(cnt[i-1][j]+cnt[i][j-1]-cnt[i-1][j-1]+mod)%mod; 44 sum[i][j]=(sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+mod)%mod; 45 if (s[i]==s[j]) 46 { 47 cnt[i][j]=(cnt[i][j]+cnt[i-1][j-1])%mod; 48 sum[i][j]=(sum[i][j]+sum[i-1][j-1]+cnt[i-1][j-1])%mod; 49 } 50 } 51 FOR(i,1,head) FOR(j,head,n) if (s[i]==s[j]) ans=(ans+er[max(0*1LL,head-i-1)]*(sum[i][j]-sum[i-1][j]-sum[i][j-1]+sum[i-1][j-1]+mod+mod)%mod)%mod; 52 return; 53 } 54 int main() 55 { 56 // freopen("clause10.in","r",stdin); 57 // freopen("myclause.out","w",stdout); 58 scanf("%s",s+1); 59 n=strlen(s+1); 60 er[0]=1; 61 FOR(i,1,n) er[i]=er[i-1]*2%mod; 62 FOR(i,1,n) solve(i); 63 write(ans);putchar('\n'); 64 return 0; 65 }