2 条题解
-
0
VOID_DC 的题解中提到了这句话:
容易发现 010 和 00010 的十进制值相同,而我们需要区分,可以直接对每个长度的子串独立开桶。
但显然不用这么麻烦。
我们把二进制换到三进制。
这一位字符 这一位对应的值 NULL(但我们不用,这一位并不会出现) 01这么赋值有什么好处呢?
-
区分了像
00101和010这样的子串。 -
按照子串的十进制值排序后得到的子串序列是按照字典序的。这样只用写双关键字排序,而非三关键字。
-
好编码,解码。
-
长度在一个区间的子串,其十进制值也在一个区间。
-
-
0
所以说多行输入字符串,折行输出是什么鬼东西,被 corner case 崩飞了。
题目传送门: vjudge链接
思路
切入点是 ,要求的字串太小了,考虑对每种长度的子串跑一个滑动窗口,复杂度 ,记录所有合法子串即可,下面有几个细节。
- 提取子串似乎可以 hash,但是没必要(其实是我不会),我们直接开桶记录子串二进制转十进制的值就可以了,通过一点位运算技巧可以在滑动的时候 实现转移。
- 容易发现 010 和 00010 的十进制值相同,而我们需要区分,可以直接对每个长度的子串独立开桶。
- 子串长度可能大于字符串长度,这种非法情况要直接特判崩掉(导致我挂分的原因)。
- 输出的时候要十进制还原二进制,还原需要十进制值和二进制位数(子串长度)。还需要按出现次数与字典序双关键字排这3个值。
- 每6个折行输出是真 cs,注意不要多输出一些奇怪的换行。
超级无敌巨帅的含注释代码
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; int ans[15][10000];//ans[i][j]: sum(len=i & number_j) int mi[13]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095};//预处理二进制下全 1 的序列 int n,m,k;string t,s; struct node{ int val,len,cnt;//十进制值,二进制长度,出现次数 }q[300000];int cnt; int ch(char x){ if(x=='1') return 1; return 0; } bool cmp(node a,node b){//三关键字排序 if(a.cnt==b.cnt){ if(a.len==b.len) return a.val<b.val; return a.len < b.len; } return a.cnt>b.cnt; } void re(int val,int len){//十进制还原二进制 string res; int rr=0; for(int i=len-1;i>=0;i--){ if(val&(1<<i)) cout << 1; else cout << 0; } return; } int main(){ cin >> n>> m >> k; while(cin >> t){s+=t;}//处理多行输入的字符串 int len=s.length(); s=" "+s; for(int i=n;i<=m;i++){ if(i>len) break;//特判非法情况 int tmp=0;//记录当前这个窗口的十进制值 for(int j=1;j<=i;j++){//处理窗口的初始位置 tmp<<=1; tmp|=ch(s[j]); } ans[i][tmp]++;//开桶记录 for(int r=i+1;r<=len;r++){ tmp<<=1;//先左移一位空位 tmp&=mi[i];//通过 $ 长为i的全1序列 去除不合法的最高位,其他位置不变 tmp|=ch(s[r]);//加入下一位 ans[i][tmp]++;//记录 } } for(int i=n;i<=m;i++){ for(int j=0;j<=9000;j++){ if(ans[i][j]){ q[++cnt]=node{j,i,ans[i][j]};//导入struct方便排序 } } } sort(q+1,q+cnt+1,cmp); int tot=0,outcnt=0; for(int i=1;i<=cnt;i++){//处理输出 if(q[i].cnt!=q[i-1].cnt&&tot==k) break; if(q[i].cnt!=q[i-1].cnt){ tot++;outcnt=0; if(i==1) cout << q[i].cnt << '\n'; else cout <<'\n'<< q[i].cnt << '\n'; } re(q[i].val,q[i].len); cout << ' '; outcnt++; if(outcnt==6){ outcnt=0; if(q[i+1].cnt==q[i].cnt) cout << '\n'; } } return 0; }
- 1
信息
- ID
- 602
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- (无)
- 递交数
- 27
- 已通过
- 7
- 上传者