[20200728NOIP提高组模拟T2]愉快的logo设计
题目大意:
今有一数,名之曰$k$,范围一至十也.先用此数构造字符串$s(k)$,$s(0)$为'J''O''I'三个字符选其一单独构成字符,此后$s(k)$为$4^{k-1}$个$J$,$4^{k-1}$个$O$,$4^{k-1}$个$I$与$s(k-1)$组成的字符串环.现给你一长度为$4^{k}$的模式串,请你求出最小的不同部分.
solution:
此题对于前$40%$数据,我们可以一一枚举起点进行匹配,复杂度$O((4^{k})^{2})$,但注意到有大量的重复且字符类型较少,于是我们可以预处理出前缀和,然后一一枚举进行计算即可,复杂度$O(3k \cdot 4^{k})$
code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define R register
#define next kdjadskfj
#define debug pust("mlg")
using namespace std;
typedef int ll;
typedef long double ld;
typedef unsigned long long ull;
inline ll read();
inline void write(ll x);
inline void writeln(ll x);
inline void writesp(ll x);
ll k;
char wn[3000000];
ll sum[3000000][4];
ll ans;
int main(){
freopen("logo.in","r",stdin);
freopen("logo.out","w",stdout);
k=read();ans=1370120724;
while(wn[1]!='J'&&wn[1]!='O'&&wn[1]!='I') wn[1]=wn[(1<<(k<<1))+1]=getchar();
for(R ll i=2;i<=(1<<(k<<1));i++){
wn[i]=wn[i+(1<<(k<<1))]=getchar();
}
for(R ll i=1;i<=((1<<(k<<1))<<1);i++){
sum[i][0]=sum[i-1][0]+(wn[i]=='J');
sum[i][1]=sum[i-1][1]+(wn[i]=='O');
sum[i][2]=sum[i-1][2]+(wn[i]=='I');
}
for(R ll s=1;s<=(1<<(k<<1));s++){
ll Tot=0,begin=s;
for(R ll i=k-1;i>=0;i--){
Tot+=sum[begin+(1<<(i<<1))-1][1]-sum[begin-1][1]+sum[begin+(1<<(i<<1))-1][2]-sum[begin-1][2];
begin+=(1<<(i<<1));
Tot+=sum[begin+(1<<(i<<1))-1][0]-sum[begin-1][0]+sum[begin+(1<<(i<<1))-1][2]-sum[begin-1][2];
begin+=(1<<(i<<1));
Tot+=sum[begin+(1<<(i<<1))-1][0]-sum[begin-1][0]+sum[begin+(1<<(i<<1))-1][1]-sum[begin-1][1];
begin+=(1<<(i<<1));
}
ans=min(ans,Tot);
}
writeln(ans);
}
inline ll read(){ll x=0,t=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') t=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*t;}
inline void write(ll x){if(x<0){putchar('-');x=-x;}if(x<=9){putchar(x+'0');return;}write(x/10);putchar(x%10+'0');}
inline void writesp(ll x){write(x);putchar(' ');}
inline void writeln(ll x){write(x);putchar('\n');}