zoukankan      html  css  js  c++  java
  • [GYM102832J]Abstract Painting

    CXXVI.[GYM102832J]Abstract Painting

    考虑将一个圆心为 \((x,0)\),半径为 \(R\) 的圆,转换为 \(x\) 轴上线段 \([x-R,x+R]\),问题转换为求无交的线段覆盖方案数。

    因为所有的圆半径很小(\(5\)),所以我们考虑状压位置 \(i\) 前面 \(10\) 位的信息(在实际应用中会发现只要状压 \(9\) 位即可,因为第 \(i-1\) 位必然为 \(0\)),表示第 \(i\) 位能否作为一个圆的左端点。当我们在位置 \(i\) 加入一个圆 \([l,i]\) 时,需要保证当前状压的状态中第 \(l\) 位为 \(0\)\(l\geq0\)\(i-l\)\(\leq10\) 的偶数。在加入这么一个圆后,第 \(l+1\sim i-1\) 位都不能作为圆的左端点,更新状态即可。同时,因为一个位置可以作为不止一个圆的右端点,所以还得枚举作为哪些圆的右端点。因为所有可能的直径只有 \(2,4,6,8,10\),所以直接 \(2^5\) 枚举即可。记得判断加入的圆的集合是否包含了必须加入的圆的集合!

    总复杂度 \(n\times2^9\times2^5\),可以通过。

    (附,通过子集枚举等trick可以将复杂度优化到 \(3^5\times 2^5\),但二者实际效率只不过差了个大约 \(2\) 的常数,而且不加也能过,就不加了)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int mod=1e9+7;
    int n,m,mus[1010],f[1010][1<<9],all=(1<<0)|(1<<2)|(1<<4)|(1<<6)|(1<<8),res;
    int fob(int ip){
    	int lim=1;
    	while(lim<=ip)lim<<=1;
    	return lim-1;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),mus[x+y]|=(1<<((y-1)<<1));
    	f[0][0]=1;
    	for(int i=1;i<=n;i++)for(int j=all;;j=(j-1)&all){
    		if((j&mus[i])==mus[i]&&j<(1<<min(i-1,9))){
    			int J=fob(j);
    //			printf("%d:%d:%d\n",i,j,J);
    			for(int k=0;k<(1<<min(i-1,9));k++){
    				if(k&j)continue;
    				(f[i][((k<<1)&((1<<9)-1))|J]+=f[i-1][k])%=mod;
    			}			
    		}
    		if(!j)break;
    	}
    	for(int i=0;i<(1<<9);i++)(res+=f[n][i])%=mod;
    	printf("%d\n",res);
    	return 0;
    } 
    

  • 相关阅读:
    Linux线程信号
    有理想的程序员必须知道的15件事
    Linux下 mplayer 使用手册
    Winxp下 gvim 编程环境搭建
    在WPF中弹出右键菜单时判断鼠标是否选中该项
    F#基本类型——Discriminated Unions
    在WPF的TreeView中实现右键选定
    WPF TreeView tools
    F#基本类型——Structure
    增强了一下DownloaderPlus的视频转换功能
  • 原文地址:https://www.cnblogs.com/Troverld/p/14601465.html
Copyright © 2011-2022 走看看