AtCoder Beginner Contest 249 E - RLE
AtCoder Beginner Contest 249 E - RLE
题意:
给定\(n(n<=3000)\),然后根据字符串的变换规则 aaaa => a4 a => a1 在变换过程中字符串的长度会发生改变,原先长度为 S ,后变为 T
问有多少种的字符串 符合变换后 T<S
思路:
先考虑该字符串中的字母为单一种类
那共有四种情况 g(x)
\(S [1,9]\) 变换后的长度为\(T=2\)
\(S [10,99]\) 变换后的长度为\(T=3\)
\(S [100,999]\) 变换后的长度为\(T=4\)
\(S [1000,3000]\) 变换后的长度为\(T=5\)
对于字符串,可以从第\(i\)位进行分析
由题意可知,在第\(i\)位后面的时另一种字母的一个字符串
比如当前遍历到的位置是 $ ....aaaa(i)bbbb....$
那这一段b的长度的不同也即是对答案的贡献,但是在\([0,3000]\)的范围内无论取何值,只有上述的四种情况。
首先定义 \(dp[i][j]\)为字符串长度为\(i变为j\)的方案数
那当我们追加这一段b(假设长度为x)时,\(dp[i+x][j+g(x)]+=25*dp[i][j]\)
但是该\(dp\)复杂度为\(N^{3}\)会超时
考虑是否可以优化为 \(n^{2}log _{n}\)
可以联想到 \(log_{n}\)的数据结构 树状数组
定义树状数组\(g[i]\)为 长度为\([1,n]\)的字符串在变换过后长度为 i 的情况,那么 \(g[i].query(n)\)即为总数
答案即为\(\sum_{i=1}^{n}dp[n][i]\)或者\(\sum_{i=1}^{n}g[i].query(n)\)
那么每一次变化时需要对\(g[j]\)进行区间更新
注意第一次更新时每一个字母都是第一次出现,所以共有26种情况,但后续更新中由于前面已经有字母出现,所以只有25种情况
代码:
#include<bits/stdc++.h>
#define de cout<<"---"<<endl;
#define ll long long
#define int long long
#define endl '\n'
using namespace std;
const ll inf =0x3f3f3f3f3f3f;
//const ll mod =998244353;//998244853
const int N=3e3+7;
ll mod;
ll qpow(ll a,ll p){if(p<1)p+=mod-1;ll ans=1;while(p){if(p&1)ans=ans*a%mod;a=a*a%mod;p>>=1;}return ans%mod;}
int n;
int lowbit(int x){return x&(-x);}
template<class T,class T2>inline void aadd(T& x,T2 y,int p=mod){
x+=y; //不加这一步好像会TLE ,因为有多次取模运算
if(x>=p)
x-=p;
}
struct BIT{
ll c[N];
inline void add(int id,ll v){
for(int i=id;i<=n;i+=i&(-i)){
aadd(c[i],v);
}
}
inline ll query(int id){
ll ans=0;
for(int i=id;i>=1;i-=i&(-i)){
aadd(ans,c[i]);
}
return ans%mod;
}
}g[3010];
ll dp[3010][3010];
void solve(){
cin>>n>>mod;
g[2].add(1,26);g[2].add(10,mod-26);
g[3].add(10,26);g[3].add(100,mod-26);
g[4].add(100,26);g[4].add(1000,mod-26);
g[5].add(1000,26);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dp[i][j]=(g[j].query(i))%mod;
if(dp[i][j]==0)continue;
g[j+2].add(i+1,25*dp[i][j]%mod);
g[j+2].add(i+10,mod-25*dp[i][j]%mod);
g[j+3].add(i+10,25*dp[i][j]%mod);
g[j+3].add(i+100,mod-25*dp[i][j]%mod);
g[j+4].add(i+100,25*dp[i][j]%mod);
g[j+4].add(i+1000,mod-25*dp[i][j]%mod);
g[j+5].add(i+1000,25*dp[i][j]%mod);
}
}
ll res=0;
for(int i=1;i<n;i++){
res=(res+g[i].query(n))%mod;
// res=(res+dp[n][i])%mod; 两种都可
}
cout<<res<<endl;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int kase=1;
// cin>>kase;
while(kase--){solve();}
}