zoukankan      html  css  js  c++  java
  • ASC47B borderless

    题目描述

    border集合为{NULL,str}的串str称为borderless串.

    border即KMP里的那个.

    字符集{'a','b'},给定长度n,求第k(给定)小的borderless串.

    题解

    按位确定,这时我们需要计算对于一个给定的前缀,以它为前缀的长k的borderless串个数.

    borderless串个数并不好求,我们考虑求有border的串个数,再容斥掉.

    考虑前缀为t的长度为j的有border串个数为ex,长度为j的borderless串个数为2^(j-min(j,t))-ex.

    考虑如何计算ex.

    枚举最短非空border长度v,首先这个border需是borderless的,否则违反"最短"性.显然这个border的数量已经计算出来了.如果中间没有限制就可以瞎jb填了,如果有限制只有可能是前缀的限制,那么border串的个数除去 2^某个数.具体实现要分类讨论一下,不太难,细节稍多.

    其实并不推荐我这样压位.害死人.

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    typedef unsigned long long ull;
    namespace bdc{
    	ull hr[64];
    	inline int borderless(ull str,int len){
    		ull a=0,b=0;
    		for(int i=0;i<len;++i){
    			a|=str&(1<<i);
    			b=(b<<1)|((str>>(len-i))&1);
    			if(a==b) return 0;
    		}
    		return 1;
    	}
    	inline void print(ull str,int len){
    		for(int i=0;i<len;++i) putchar('a'+((str>>i)&1));
    	}
    	inline ull calc(int n,ull k){
    		ull ans=0;
    		for(int i=0;i<n;++i){
    			hr[0]=1;
    			for(int j=1;j<=i;++j){
    				hr[j]=borderless(ans,j);
    			}
    			for(int j=i+1;j<n;++j){
    				hr[j]=0;
    				for(int k=0;k+k<=j-1;++k){
    					int v=std::max(i,k); // prefix that has been determined
    					if(k+v+1>j){ // if overlapped
    						int vt=k+v+1-j;
    						ull mask=(1ull<<vt)-1;
    						if((ans&mask) == ((ans>>(j-k))&mask)){
    							hr[j]+=hr[k]; // if can into border
    						}
    					}
    					else{
    						hr[j]+=hr[k]<<(j-k-v-1); // if not overlapped, then [border][len(xjbstr|NULLStr)=j-k-v][border]
    					}
    				} /// count bordered strings
    				hr[j]=(1ull<<(j-i))-hr[j]; /// to borderless
    			}
    			if(k>hr[n-1]){
    				k-=hr[n-1];
    				ans|=1ull<<i;
    			}
    		}
    		return ans;
    	}
    }
    int main(){
    	freopen("borderless.in","r",stdin);
    	freopen("borderless.out","w",stdout);
    	int n;
    	ull b;
    	while(~scanf("%d%llu",&n,&b)){
    		using namespace bdc;
    		if(!n && !b) return 0;
    		print(calc(n,b),n);
    		putchar('
    ');
    	}
    	return 0;
    }
    

    经验与教训

    位运算害人.(1<<63)==(1<<31).注意正确写法应为(1ull<<63)

  • 相关阅读:
    ASP.NET零碎
    My97DatePicker 和转换 数据库中日期(/Date(1351699200000)/) 的格式
    生成验证码
    自己封装的AJAX (带JSON)
    WebForm
    配置进程外Session
    使用Xcode和Instruments调试解决iOS内存泄露
    IOS block 教程<转>
    iOS app支付宝接口调用的一点总结(补充支付宝SDK&Demo下载地址)
    支付宝在ios应用上的开发[转]
  • 原文地址:https://www.cnblogs.com/tmzbot/p/5373108.html
Copyright © 2011-2022 走看看