P5362 [SDOI2019]連續子序列 思維題
阿新 • • 發佈:2021-01-09
題意:
分析:
不會分析 , 直接找規律:
肉眼分析可以發現, \(T.M\) 序列的生成方式有兩種:
- 取反然後複製一遍 \(0110\to 01101001\)
- \(\tiny \color{white}{\text{不}}\)容易發現 \(0110\to 0(1)1(0)1(0)0(1)\)
但是第一個性質不方便用,因為 \(|S|+k\) 不一定是 \(2\) 的整數次冪,所以我們考慮第二種方法
我們發現在後面新增的 \(k\) 的布林序列也會是 \(01\) ,\(10\) 交替的,所以一定不會存在連續的三個以上的相同字元,所以我們可以反向推導,由第二個性質可以知道 \(0\to 01\) \(1\to 10\)
具體來說就是,每次分兩種情況討論,一種是第一位空出來與前面的拼成一個 \(0\),第二種就是從第一位開始兩個一組
程式碼:
#include<bits/stdc++.h> #define pii pair<int,int> #define mk(x,y) make_pair(x,y) #define lc rt<<1 #define rc rt<<1|1 #define pb push_back #define fir first #define sec second #define psl pair<string,long long> using namespace std; namespace zzc { typedef long long ll; const ll mod = 1e9+9; map<psl,ll> f; long long solve(string s,long long k) { if(f[mk(s,k)]) return f[mk(s,k)]; long long n=s.size(),res=0; if(n==1&&k<=2) return k+1; if(n==2&&k==0) return 1; if(n==2&&k==1) return (s[0]==s[1])?1:2; if(n==3&&k==0) return (s[0]!=s[1]||s[1]!=s[2]); bool flag=true; string nxt; for(int i=0;i<n;i+=2) { if(i==n-1||s[i]!=s[i+1]) nxt+=s[i]; else {flag=false;break;} } if(flag) res+=solve(nxt,(n&1)?(k>>1):((k+1)>>1))%mod; nxt=((s[0]-'0')^1)+'0'; flag=true; for(int i=1;i<n;i+=2) { if(i==n-1||s[i]!=s[i+1]) nxt+=s[i]; else {flag=false;break;} } if(flag) res+=solve(nxt,(n&1)?((k+1)>>1):(k>>1))%mod; return f[mk(s,k)]=res%mod; } void work() { ios::sync_with_stdio(false); string s; ll k,t; cin>>t; while(t--) { cin>>s>>k; cout<<solve(s,k)%mod<<'\n'; } } } int main() { zzc::work(); return 0; }