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\)

\[g(x) = \begin{cases} 2 ,&1<=x<10 \\ 3 ,&10<=x<100 \\ 4 ,&100<=x<1000 \\ 5 ,&1000<=x<=3000 \\ \end{cases} \]

对于字符串,可以从第\(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();}
}

posted @ 2022-04-25 19:22  LiAnG24  阅读(90)  评论(0)    收藏  举报