题目描述:
FST是一名可怜的 OIer,他很强,但是经常 fst,所以 rating 一直低迷。
但是重点在于,他真的很强!他发明了一种奇特的加密方式,这种加密方式只有OIer才能破解。
这种加密方式是这样的:对于一个 01 串,他会构造另一个 01 串,使得原串是在新串中没有出现过的最短的串。
现在 FST 已经加密好了一个串,但是他的加密方式有些 BUG ,导致没出现过的最短的串不止一个,他感觉非常懊恼,所以他希望计算出没出现过的最短的串的长度。
输入格式:
一行,一个 01 串。
输出格式:
一行,一个正整数,表示没有出现过的最短串的长度。
样例输入:
100010110011101
样例输出:
4
数据范围:
测试点 1、2、3 的串长度≤10;
测试点 3、4、5 的串长度≤100;
测试点 6、7、8、9、10 的串长度≤105;
题目分析:
考虑一个长度为i的串,显然它的排列组合共有2i种。对于给定的01串,如果一个长度为i的串在其中出现了不同的2i次,那么长度i的串就不存在没有过出现的情况,反之则有。因为给定01串长度最大为105,所以我们寻找的子串长度不超过17(217>105)。二分这个长度x(当然直接枚举也行,我二分的是1到20)。检查时,从原01串里依次取出长度为x的串,将其转为十进制,然后用check1数组标记,统计有多少个不同串。如果数目等于2x,则x还需增大,反之x减小。
总结:本来这是一道简单题,结果因为一个小错误导致只得了60分,跟一个暴力一样······我错在每次取出串放在一个数组里去转进制,数组我会清0,外面是有一个for循环,这个循环最大是O(n=105),本来数组大小是20就行,清0复杂度最大也就105∗20/32(memset的复杂度是O(n/32)),但我随手把数组大小赋成了105(因为其他数组的大小都是这个),然后就炸了,硬生生变成了105∗105/32。所以做题的时候要细心,要认真算一下复杂度,以前我做题算复杂度都忽略了清0操作,吃一堑长一智······
附代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<queue>
#include<set>
#include<map>
#include<cctype>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
long long num,len,tot,a[maxn],s[20],d,b,ans;
bool check1[maxn];
char ss[maxn];
int ksm(int y)
{
int ret=1;
for(int x=2;y;x*=x,y/=2)
if(y&1) ret*=x;
return ret;
}
int zjz()//二进制转十进制
{
int mi=1,sum=0;
sum=s[len-1];
for(int i=len-2;i>=0;i--)
{
mi=mi*2;
sum=sum+s[i]*mi;
}
return sum;
}
bool check(int x)
{
num=0;
d=ksm(x);
if(d>tot) return false;
memset(check1,false,sizeof(check1));
for(int i=1;i<=tot-x+1;i++)
{
len=0;
memset(s,0,sizeof(s));
for(int j=i;j<=i+x-1;j++)
s[len++]=a[j];
b=zjz();
if(check1[b]==false)
{
num++;
check1[b]=true;
}
}
if(num<d) return false;
if(num==d) return true;
}
int half()
{
int l=1,r=20,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid)==true)
l=mid+1;
else
r=mid-1;
}
return l;
}
int main()
{
//freopen("fst.in","r",stdin);
//freopen("fst.out","w",stdout);
scanf("%s",ss+1);
tot=strlen(ss+1);
for(int i=1;i<=tot;i++)
a[i]=ss[i]-'0';
ans=half();
printf("%I64d",ans);
return 0;
}
这是一篇关于NOIP模拟题目的解析,主要讨论了一种特殊的01串加密方式。题目要求找到未出现过的最短串的长度。通过分析2的幂次与01串长度的关系,采用二分查找的方法来确定最短未出现串的长度。在实现过程中,由于细节处理不当导致原本简单的算法变得复杂,从而引发了性能问题。作者提醒做题时要仔细计算复杂度并避免不必要的错误。

462

被折叠的 条评论
为什么被折叠?



