zoukankan      html  css  js  c++  java
  • loj2540 「PKUWC 2018」随机算法

    pkusc 快到了……做点题涨涨 rp。

    (f(S,i)) 表示 (S) 这个集合是决计不能选的(要么属于独立集,要么和独立集相连),或称已经考虑了的,(i) 表示此集合对应的最大独立集大小。那么枚举一下哪些点 (j) 不在 (S) 里,记 (w_i) 表示 (i) 和与之相邻的点集,则 (f(S cup w_j,i+1) leftarrow f(S cup w_j,i+1) + f(S,i) imes A_{n-|S|-1}^{|w_j-(w_j cap S)|-1})

    然而对于一个集合 (S),它的最大独立集大小是确定的,那么就来一个数组 (mx_S) 来记录其最大独立集大小。当最大独立集大小更新之时,(dp_S) 就清零然后再计数就行了。复杂度从 (O()跑得过()) 变成了 (O()更跑得过()),也就是(O(n^22^n)) 变成了 (O(n2^n))……。

    改进前:

    #include <iostream>
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    int n, m, w[25], uu, vv, jie[25], inv[25], dp[25][1050005], cnt[1050005];
    const int mod=998244353;
    int A(int x, int y){
    	// if(x<y)	return 0;
    	return (ll)jie[x]*inv[x-y]%mod;
    }
    int main(){
    	cin>>n>>m;
    	for(int i=1; i<=m; i++){
    		scanf("%d %d", &uu, &vv);
    		uu--; vv--;
    		w[uu] |= 1<<vv;
    		w[vv] |= 1<<uu;
    	}
    	jie[0] = jie[1] = inv[0] = inv[1] = 1;
    	for(int i=2; i<=n; i++){
    		jie[i] = (ll)jie[i-1] * i % mod;
    		inv[i] = (ll)(mod - mod / i) * inv[mod%i] % mod;
    	}
    	for(int i=0; i<n; i++)
    		w[i] |= 1<<i;
    	for(int i=2; i<=n; i++)
    		inv[i] = (ll)inv[i-1] * inv[i] % mod;
    	for(int i=0; i<(1<<n); i++)
    		for(int j=0; j<n; j++)
    			if(i&(1<<j))
    				cnt[i]++;
    	dp[0][0] = 1;
    	for(int i=0; i<n; i++)
    		for(int s=0; s<(1<<n); s++)
    			if(dp[i][s])
    				for(int j=0; j<n; j++)
    					if(!(s&(1<<j)))
    						dp[i+1][s|w[j]] = (dp[i+1][s|w[j]] + (ll)dp[i][s] * A(n-cnt[s]-1, cnt[w[j]-(w[j]&s)]-1)%mod) % mod;
    	for(int i=n; i; i--)
    		if(dp[i][(1<<n)-1]){
    			cout<<(ll)dp[i][(1<<n)-1]*inv[n]%mod<<endl;
    			return 0;
    		}
    	return 0;
    }
    

    改进后:

    #include <iostream>
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    int n, m, w[25], uu, vv, jie[25], inv[25], dp[1050005], cnt[1050005];
    int mx[1050005];
    const int mod=998244353;
    int A(int x, int y){
    	// if(x<y)	return 0;
    	return (ll)jie[x]*inv[x-y]%mod;
    }
    int main(){
    	cin>>n>>m;
    	for(int i=1; i<=m; i++){
    		scanf("%d %d", &uu, &vv);
    		uu--; vv--;
    		w[uu] |= 1<<vv;
    		w[vv] |= 1<<uu;
    	}
    	jie[0] = jie[1] = inv[0] = inv[1] = 1;
    	for(int i=2; i<=n; i++){
    		jie[i] = (ll)jie[i-1] * i % mod;
    		inv[i] = (ll)(mod - mod / i) * inv[mod%i] % mod;
    	}
    	for(int i=0; i<n; i++)
    		w[i] |= 1<<i;
    	for(int i=2; i<=n; i++)
    		inv[i] = (ll)inv[i-1] * inv[i] % mod;
    	for(int i=0; i<(1<<n); i++)
    		for(int j=0; j<n; j++)
    			if(i&(1<<j))
    				cnt[i]++;
    	dp[0] = 1;
    	for(int s=0; s<(1<<n); s++)
    		if(dp[s])
    			for(int i=0; i<n; i++)
    				if(!(s&(1<<i))){
    					int t=s|w[i];
    					if(mx[t]<mx[s]+1)	mx[t] = mx[s] + 1, dp[t] = 0;
    					if(mx[t]==mx[s]+1)
    						dp[t] = (dp[t] + (ll)dp[s] * A(n-cnt[s]-1, cnt[w[i]-(w[i]&s)]-1)%mod) % mod;
    				}
    	cout<<(ll)dp[(1<<n)-1]*inv[n]%mod<<endl;
    	return 0;
    }
    
  • 相关阅读:
    获取Android控件宽高
    Android面试题:大图加载,防止OOM
    Android面试题:讲一讲Glide的原理
    面试题:实现一个容器,提供两个方法,add,size;写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束
    Java线程中断的三种方法
    Java的四种引用:强引用、软引用,弱引用和虚引用
    Bellman-Ford(可解决负权边)--时间复杂度优化
    【Leetcode 动态规划、深度优先搜索】不同路径(62)、 不同路径 II(63)、不同路径 III(980)
    ElasticSearch scroll分页查询
    MySQL Myisam引擎和Innodb引擎的区别
  • 原文地址:https://www.cnblogs.com/poorpool/p/9069285.html
Copyright © 2011-2022 走看看