20180407模擬賽T1——Pro1
阿新 • • 發佈:2018-04-07
pty AC gets -i blog str ring tin rand()
吐槽這題目名取得……
Pro1
為了入侵m*的機器,m__想了很多方法套m的密碼。現在他終於得出了一個重要信息:m的密碼是一個回文串。m__從m*處套出了若幹個字符串,m__想知道對於每個字符串,最少可以在字符串最後加多少個字符,使得新字符串有可能成為密碼。
數據範圍
對於60%的數據 字符串長度≤103
對於100%的數據 字符串長度≤105 數據組數≤10
輸入格式
若幹行,每行一個字符串
輸出格式
若幹行,每行一個回文串
樣例
Pro1.in
aaaa
abba
amanaplanacanal
xyz
Pro1.out
aaaa
abba
amanaplanacanalpanama
xyzyx
題解
這題暴力分還是挺多的。暴力麽……主要是求最長回文字串嘛……
隨便貼一份暴力
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
typedef long long ll;
#define dd c=getchar()
inline ll read(){
ll x=0,f=1;char dd;
for(;!isdigit(c);dd)if(c==‘-‘)f=-1;
for(;isdigit(c);dd)x=(x<<1 )+(x<<3)+(c^48);
return x*f;
}
#undef dd
inline void write(ll x){
if(x<0)putchar(‘-‘),x=-x;
if(x>9)write(x/10);putchar(x%10|48);
}
const ll N=1e5+10;
char a[N];ll len;
inline bool check1(ll mid){
for (ll i=1;mid+i<=len;i++)
if (a[mid-i]!=a[mid+i]) return 0;
for (ll j=mid*2 -len-1;j>0;j--) putchar(a[j]);
puts("");
return 1;
}
inline bool check(ll mid){
for (ll i=1;mid+i-1<=len;i++)
if (a[mid-i]!=a[mid+i-1]) return check1(mid);
for (ll j=(mid-1)*2-len;j>0;j--) putchar(a[j]);
puts("");
return 1;
}
int main(){
freopen("pro1.in","r",stdin);
freopen("pro1.out","w",stdout);
while (scanf("%s",a+1)!=EOF){
len=strlen(a+1);
printf("%s",a+1);
for (ll i=len>>1;i<=len;i++)
if (check(i)) break;
}return 0;
}
我的wa暴力
#include <cstdio>
#include <cstring>
#include <queue>
#define deb 0
using namespace std;
char a[100005];
queue<int>que;
char t;
inline bool pan(int l,int r)
{
while(l<r)
{
if(a[l]==t) que.push(l);
if(a[l]^a[r])return false;
l++;r--;
}
return true;
}
inline bool pan2(int l,int r)
{
while(l^r)
{
if(a[l]^a[r])return false;
l++;r--;
}
return true;
}
int main()
{
#if !deb
freopen("pro1.in","r",stdin);
freopen("pro1.out","w",stdout);
#endif
while(gets(a))
{
int ttt=0;
int len=strlen(a);
t=a[len-1];
#if deb
putchar(t);
puts("");
#endif
for(int i=0;i<len;++i)
if(t==a[i])
{
if(pan(i,len-1))
{
ttt=i;
break;
}
while(!que.empty())
{
i=que.front();
if(pan2(i,len-1))
{
ttt=i;
goto L1;
}
que.pop();
}
}
L1:;
if(ttt==0)
{
puts(a);
continue;
}
for(int i=0;i<ttt;++i)putchar(a[i]);
for(int i=len-1;i>=0;--i)putchar(a[i]);
puts("");
}
#if !deb
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
蛙的原因是只考慮回文串的字符個數是奇數的狀態(只同時向左向右拓展)。
於是,為了防止這個錯誤,我們可以在每兩個字符之間加一個‘#‘或’%‘(反正該一些奇怪的字符)
gets(ch+1);
len=strlen(ch+1);
for(int i=1;i<=len;++i)s[i<<1]=ch[i],s[i<<1|1]=‘#‘;
s[1]=-1,s[len<<1|1]=-2;//賦一些奇怪的字符
len=len<<1|1;//拓展後的len
於是就變成了Manacher算法
#include <cstdio>
#include <cstring>
using namespace std;
char ch[100005],s[200005];
int len,ppp,ok,ans[200005];
int main()
{
freopen("pro1.in","r",stdin);
freopen("pro1.out","w",stdout);
while(gets(ch+1))
{
len=strlen(ch+1);
for(int i=1;i<=len;++i)s[i<<1]=ch[i],s[i<<1|1]=‘#‘;
s[1]=-1,s[len<<1|1]=-2;//賦一些奇怪的字符
len=len<<1|1;//拓展後的len
ans[1]=0;ok=1;ans[len]=1;
int tot=0;
for(int i=2;i<len;++i)
{
ans[i]=(i>ok+ans[ok])?0:ans[(ok<<1)-i];
if(i<=ok+ans[ok]&&i+ans[i]>ans[ok]+ok) ans[i]=ok+ans[ok]-i;
while(s[i-ans[i]-1]==s[i+ans[i]+1])ans[i]++,tot++;
if(i+ans[i]>ok+ans[ok]) ok=i;
}
ppp=len;
for(int i=2;i<len;++i)
if(i+ans[i]==len-1)
{
ppp=i;break;
}
for(int i=1;i<=len;++i) if(!(i&1)) putchar(s[i]);
for(int i=ppp-ans[ppp]-1;i;--i) if(!(i&1)) putchar(s[i]);
puts("");
}
fclose(stdin);fclose(stdout);return 0;
}
讓我們再來看看zhaotiesn大佬的玄學做法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
using namespace std;
#define Max 1000005
int n,l,r,mid,num[200],sum[Max];
char s[Max];
bool flag;
inline bool check(int x){
/*for(int i=x+1;i<=((n+x+1)>>1);i++){
if(s[i]!=s[n-i+x+1])return false;
}*/
// cout<<n<<" "<<(n+x)/2<<" "<<(n+x+1)/2<<" "<<x<<endl;
if(sum[n]-sum[(n+x)/2]==sum[(n+x+1)/2]-sum[x]){
for(int i=x+1;i<=((n+x+1)>>1);i++){
if(s[i]!=s[n-i+x+1])return false;
}
return true;
}else return false;
}
int main(){
freopen("pro1.in","r",stdin);
freopen("pro1.out","w",stdout);
srand((int)time(NULL));
for(int i=1;i<=200;i++)num[i]=rand()*rand()^rand()*rand()^rand();
while(scanf("%s",s+1)!=EOF){
n=strlen(s+1);flag=false;
sum[0]=0;
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+num[int(s[i])];
for(int i=0;i<=n;i++){
if(check(i)){
printf("%s",s+1);
for(int j=i;j>=1;j--){
// printf("%c",s[j]);
putchar(s[j]);
}
puts("");
flag=true;
}
if(flag)break;
}
}
return 0;
}
20180407模擬賽T1——Pro1