1. 程式人生 > >USACO 3.1 聯絡

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;
}