USACO 3.1 联系
这题巨多坑点啊,就算算法对了也D了半个小时orz
看到题目,我的想法是记录每种串的出现次数,将串转成二进制计算值即可。由于010和0010可能被重复计在一起,所以要限制长度k
所以,用cnt[k][i]表示长度为k,值为i的串的出现次数
但稍等!如果我们每个串都计算一次,那么是会超时的,这里就要用到一个技巧:滚动哈希
考虑一个串110110101,长度为3,现在我们算出了110的哈希值为5,那么怎么算下一位101的值呢?
稍加分析即可发现,我们将110向左移一位变成1100,现在我们得去掉最高位的1,就将它& ((1<<k) - 1)(即为0111,这样就除去了超过三位的数字),再将它或目前的值,就能O(1)得到当前哈希值
这样,复杂度就为O(nb),可以通过本题
但这道题的坑点不在此,而是输出和特判!!
输出的换行和细节具体见代码,还有就是如果a > b直接return 0 ,如果b > len,那么将b变为len即可,见代码
以上
时间:2.0h
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<climits>
#include<queue>
using namespace std;
const int maxn = 2e5 + 5;
inline int read()
{
int ans = 0,op = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-') op = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
(ans *= 10) += ch - '0';
ch = getchar();
}
return ans * op;
}
int aa,b,n;
int cnt[13][1 << 12];
char s[maxn];
char ss[110];
int a[maxn];
int invert(int s,int e)
{
int ans = 0;
for(int i = s;i <= e;i++)
{
(ans += a[i]) *= 2;
//cout << a[i];
}
return ans >> 1;
}
int ans[20];
void rebuild(int k,int len)
{
int temp = len;
memset(ans,0,sizeof(ans));
while(len--)
{
ans[len] = k & 1;
k = k >> 1;
}
for(int i = 0;i < temp;i++) printf("%d",ans[i]);
}
struct node
{
int v,len,tv;
bool operator < (const node& a) const
{
if(v != a.v) return v > a.v;
else if(len != a.len) return len < a.len;
else return tv < a.tv;
}
}st[maxn];
int top;
int len;
int main()
{
aa = read(),b = read(),n = read();
while(scanf("%s",ss + 1) != EOF)
{
for(int i = 1;i <= strlen(ss + 1);i++)
{
len++;
s[len] = ss[i];
}
}
b = min(b,len);
if(aa > b) return 0;
for(int i = 1;i <= len;i++) a[i] = s[i] - '0';
for(int k = aa;k <= b;k++)
{
int temp = invert(1,1 + k - 1);
cnt[k][temp]++;
for(int i = k + 1;i <= len;i++)
{
temp = ((temp << 1) & ((1 << k) - 1)) | a[i];
cnt[k][temp]++;
}
}
for(int k = aa;k <= b;k++)
for(int i = 0;i <= (1 << k) - 1;i++)
if(cnt[k][i]) st[++top].v = cnt[k][i],st[top].len = k,st[top].tv = i;
sort(st + 1,st + 1 + top);
int j = 1;
for(int i = 1;i <= n;i++)
{
if(j > top) break;
printf("%d\n",st[j].v);
int tot = 1;
rebuild(st[j].tv,st[j].len);
printf(" ");
while(st[j].v == st[j + 1].v && j + 1 <= top)
{
j++;
rebuild(st[j].tv,st[j].len);
tot++;
printf(" ");
if(tot >= 6) { printf("\n"); tot = 0; }
}
j++;
if(tot) printf("\n");
}
//cout << endl;
}