码迷,mamicode.com
首页 > 其他好文 > 详细

[SDOI2019] 连续子序列

时间:2020-06-13 17:22:17      阅读:73      评论:0      收藏:0      [点我收藏+]

标签:res   根据   ffffff   布尔   hide   ===   amp   string   pre   

题意:

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

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

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

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

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

$数据组数T\leq 100,|S|\leq 100,k\leq 10^{18}$。

 

题解:

神仙诈骗题。

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

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

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

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

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

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

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

 

套路:

  • 根据数据范围猜做法,跳出思维定势;
  • 想了一会算不了的可能真算不了,别瞎编做法了。

 

代码:

技术图片
#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\n",solve(S,k));
    }
    return 0;
}
连续子序列

 

[SDOI2019] 连续子序列

标签:res   根据   ffffff   布尔   hide   ===   amp   string   pre   

原文地址:https://www.cnblogs.com/YSFAC/p/13112960.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!