[SDOI2019] 连续子序列

题意:

我们定义TM序列为如下形式的布尔序列:

  • $T_0 = 0$;
  • $T_{2n}=T_n$;
  • $T_{2n+1}=1-T_n$。

TM序列是一个无限长度的序列,它有很多连续子序列。

现在给定一个布尔序列S和一个非负整数k,请统计一下一共有多少种TM序列的连续子序列T满足:

  • S是T的前缀;
  • T是由S额外在右侧添加了恰好k项形成的。

$数据组数Tleq 100,|S|leq 100,kleq 10^{18}$。

题解:

神仙诈骗题。

该序列的生成方式有无数种,我一开始想的是每次取反拼在后面,但好像没什么操作空间。

注意到k的范围是$10^{18}$,这个数据范围要么是$O(1)$要么是$O(log{k})$。

发现自己不会$O(1)$,于是考虑$O(log{k})$,也就是每次把长度压缩成原来的一半。

考虑该序列的另外一个生成方式:每次将0替换成01,将1替换成10。我们反着做这个操作即可压缩序列。

虽然这k个空填啥都行,但仔细想一下,缩的过程中它们都会跟某个确定的元素配对一次,实际上没有累加贡献。

注意每次缩的时候都有两种情况:把第一个元素跟前面/后面配对,在$nleq 3$的时候还得特判一下。

复杂度$O(log{k})$,因为每个串最后只能缩成一个串。

套路:

  • 没思路$ ightarrow$根据数据范围猜做法。
  • 想了一会还是没思路$ ightarrow$直接写个优秀的暴力走人。

代码:

#include<bits/stdc++.h>
#define maxn 100005
#define maxm 500005
#define inf 0x7fffffff
#define mod 1000000009
#define ll long long
#define mp make_pair
#define rint register int
#define debug(x) cerr<<#x<<": "<<x<<endl
#define fgx cerr<<"--------------"<<endl
#define dgx cerr<<"=============="<<endl

using namespace std;
map<pair<string,ll>,ll> dp;
string S;

inline ll read(){
    ll x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}

inline ll solve(string s,ll k){
    if(dp[mp(s,k)]) return dp[mp(s,k)];
    ll n=s.length(),res=0;
    if(n==1 && k<=2) return dp[mp(s,k)]=k+1;
    if(n==2 && k==0) return dp[mp(s,k)]=1;
    if(n==2 && k==1) return dp[mp(s,k)]=(s[0]==s[1])?1:2;
    if(n==3 && k==0) return dp[mp(s,k)]=(s[0]!=s[1]||s[1]!=s[2]); 
    string ns; bool flag=1;
    for(rint i=0;i<n;i+=2){
        if(i==n-1 || s[i]!=s[i+1]) ns+=s[i];
        else{flag=0;break;}
    }
    if(flag) res=(res+solve(ns,(n&1)?(k>>1):((k+1)>>1)))%mod;
    flag=1,ns=((s[0]-'0')^1)+'0';
    for(rint i=1;i<n;i+=2){
        if(i==n-1 || s[i]!=s[i+1]) ns+=s[i];
        else{flag=0;break;}
    }
    if(flag) res=(res+solve(ns,(n&1)?((k+1)>>1):(k>>1)))%mod;
    return dp[mp(s,k)]=res;
}

int main(){
    ll T=read();
    while(T--){
        dp.clear();
        cin>>S; ll k=read();
        printf("%d
",solve(S,k));
    }
    return 0;
}
连续子序列
原文地址:https://www.cnblogs.com/YSFAC/p/13112960.html