zoukankan      html  css  js  c++  java
  • 「PKUWC2018」随机算法

    题目

    思博状压写不出是不是没救了呀

    首先我们直接状压当前最大独立集的大小显然是不对的,因为我们的答案还和我们考虑的顺序有关

    我们发现最大独立集的个数好像不是很多,可能是(O(n))级别的,于是我们考虑从这个方面入手

    我们求出所有的最大独立集,考虑求出有多少种考虑顺序能够恰好得到这个最大独立集

    设当前已经考虑的点的状态为(S)时的方案数为(dp_S)

    我们考虑枚举出一个不在状态(S)的点(x)

    分两种情况

    1. (x)是最大独立集的点,所以我们可以把这个点加入(S)

    2. (x)不是最大独立集的点,我们发现只有当和这个点相邻的且属于最大独立集的点加入(S),我们才能加入(x),这样(x)才能不被加入独立集

    于是我们这样做就好啦,复杂度是(O(2^nn^2)),卡卡常数就过去啦

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    #define lb(x) ((x)&(-x))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int maxn=(1<<20)+5;
    const int mod=998244353;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    int st[maxn][21],top[maxn];
    int cnt[maxn],f[maxn],vis[22],tot,ans,inv[22];
    int n,m,N,d[22],g[maxn],dp[maxn],lg[maxn];
    inline int chk(int S) {
    	int t=S;
    	while(t) {
    		int x=lg[lb(t)];
    		t-=lb(t);
    		if(d[x]&S) return 0;
    	}
    	return 1;
    }
    inline void get(int S,int p) {
    	int t=S;
    	while(t) {
    		int x=lg[lb(t)];
    		t-=lb(t);st[p][++top[p]]=x;
    	}
    }
    inline int qm(int a) {return a>=mod?a-mod:a;}
    inline int calc(int S) {
    	int t=S;memset(vis,0,sizeof(vis));
    	while(t) {
    		int x=lg[lb(t)];
    		t-=lb(t);vis[x]=1;
    	}
    	memset(dp,0,sizeof(dp));
    	dp[0]=1;
    	for(re int i=0;i<N;i++) {
    		for(re int j=1;j<=top[i];j++) {
    			int x=st[i][j];
    			if(vis[x]||(d[x]&S&i)) 
    				dp[i|(1<<(x-1))]=qm(dp[i|(1<<(x-1))]+dp[i]);
    		}
    	} 
    	return dp[N];
    }
    int main() {
    	n=read(),m=read();N=(1<<n)-1;
    	for(re int i=1;i<=N;i++) cnt[i]=cnt[i>>1]+(i&1);
    	for(re int x,y,i=1;i<=m;i++) {
    		x=read(),y=read();
    		d[x]|=(1<<(y-1));d[y]|=(1<<(x-1));
    	}
    	for(re int i=1;i<=n;i++) lg[1<<(i-1)]=i;
    	for(re int i=0;i<=N;i++)  get(N^i,i);
    	for(re int i=1;i<=N;i++) f[i]=chk(i);
    	for(re int i=1;i<=N;i++) if(f[i]&&cnt[i]>cnt[ans]) ans=i;
    	for(re int i=1;i<=N;i++) 
    		if(f[i]&&cnt[i]==cnt[ans]) 
    			tot=qm(tot+calc(i));
    	inv[1]=1;
    	for(re int i=2;i<=n;i++) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    	for(re int i=2;i<=n;i++) tot=(1ll*tot*inv[i])%mod;
    	printf("%d
    ",tot);
    	return 0;
    }
    

    至于(O(2^nn))的正解好像很神仙的样子,大概是加入一个点的时候把和它相连的点都加入进来,转移的过程中还要乘上排列数,一看我就不会,于是就不写啦

  • 相关阅读:
    命令式语言和声明式语言对比——JavaScript实现快速排序为例
    merge sort 的javascript实现
    快速排序算法的简短描述
    Hadoop 2.x 版本的单机模式安装
    数据分析招聘网招聘信息分析报告
    使用PROC TRANSPOSE过程步对数据集进行转置时如何保持日期变量的时间顺序
    饼图微创意
    我的微博关键字
    QQ群成员发言次数统计(词云制作)
    在SAS数据步中执行过程步的简单示例
  • 原文地址:https://www.cnblogs.com/asuldb/p/10714722.html
Copyright © 2011-2022 走看看