• 「PKUWC2018」随机算法


    题面

    题解

    简单状压$dp$

    我们考虑把一个点放进独立集中,

    所有与它相邻的点和还没有考虑的点在后面任意一个位置都对答案没有影响

    其中我们认为考虑了一个点,当且仅当这个点在独立集中或者与独立集中的点联通

    那么枚举下一个考虑的点,这个点一定可以加入独立集

    设$f[i][S]$表示独立集大小为$i$,已经考虑的点集为$S$的方案数

    记忆化搜索即可

    代码

    #pragma GCC target ("popcnt")
    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    #define RG register
    #define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
    #define clear(x, y) memset(x, y, sizeof(x))
    
    inline int read()
    {
    	int data = 0, w = 1; char ch = getchar();
    	while(ch != '-' && (!isdigit(ch))) ch = getchar();
    	if(ch == '-') w = -1, ch = getchar();
    	while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
    	return data * w;
    }
    
    #define pcnt __builtin_popcount
    const int Mod(998244353), maxn(30), LIM(1 << 20);
    inline int Add(int x, int y) { return (x + y) % Mod; }
    
    int n, m, a[maxn], Ans, f[maxn][LIM], P[maxn][maxn], S;
    bool vis[maxn][LIM];
    int dp(int x, int y)
    {
    	if(vis[x][y]) return f[x][y];
    	vis[x][y] = true;
    	if(y == S) return (f[x][y] = (x == Ans));
    	for(RG int i = 0; i < n; i++)
    		if(!(y & (1 << i)))
    		{
    			int newy = y | (1 << i) | a[i];
    			f[x][y] = Add(f[x][y], 1ll * dp(x + 1, newy) *
    					P[n - pcnt(y) - 1][pcnt(a[i] & (S ^ y))] % Mod);
    		}
    	return f[x][y];
    }
    
    int fastpow(int x, int y)
    {
    	int ans = 1;
    	while(y)
    	{
    		if(y & 1) ans = 1ll * ans * x % Mod;
    		x = 1ll * x * x % Mod, y >>= 1;
    	}
    	return ans;
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	file(cpp);
    #endif
    	S = (1 << (n = read())) - 1, m = read();
    	for(RG int i = 0; i <= n; i++)
    	{
    		P[i][0] = 1;
    		for(RG int j = 1; j <= i; j++)
    			P[i][j] = 1ll * P[i][j - 1] * (i - j + 1) % Mod;
    	}
    	for(RG int i = 1, x, y; i <= m; i++)
    	{
    		x = read() - 1, y = read() - 1;
    		a[x] |= (1 << y),
    		a[y] |= (1 << x);
    	}
    	Ans = 0; int s, f;
    	for(RG int i = 1; i <= S; i++)
    	{
    		f = 1, s = pcnt(i);
    		if(s < Ans) continue;
    		for(RG int j = 0; j < n; j++)
    			if((i & (1 << j)) && (i & a[j])) { f = 0; break; }
    		if(f) Ans = s;
    	}
    
    	s = 1;
    	for(RG int i = 1; i <= n; i++) s = 1ll * s * i % Mod;
    	printf("%lld
    ", 1ll * dp(0, 0) * fastpow(s, Mod - 2) % Mod);
    	return 0;
    }
    
  • 相关阅读:
    jQuery学习教程(一):入门
    jQuery学习教程(八):事件
    jQuery学习教程(五):选择器综合实例
    jQuery学习教程(六):属性操作与CSS操作
    jQuery学习教程(四):使用jQuery操作DOM
    jQuery学习教程(七):val()与节点操作
    jQuery学习教程(二):选择器1
    const的使用
    ASP.NET 页面间传值的方法
    .net中接口与基类
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/10211448.html
Copyright © 2020-2023  润新知