• P4841 城市规划 FFT+生成函数


    (color{#0066ff}{ 题目描述 })

    刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了. 刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案. 好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目. 由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可.

    (color{#0066ff}{输入格式})

    一行,四个整数,N、M、x、|S|,其中|S|为集合S中元素个数。第二行,|S|个整数,表示集合S中的所有元素。

    (color{#0066ff}{输出格式})

    一行,一个整数,表示你求出的种类数mod 1004535809的值。

    (color{#0066ff}{输入样例})

    3
        
    4
        
    100000
    

    (color{#0066ff}{输出样例})

    4
       
    38
        
    829847355
    

    (color{#0066ff}{数据范围与提示})

    对于 20%的数据, n <= 10

    对于 40%的数据, n <= 1000

    对于 60%的数据, n <= 30000

    对于 80%的数据, n <= 60000

    对于 100%的数据, n <= 130000

    (color{#0066ff}{ 题解 })

    from rqj

    直接构造出g,求个ln(指数生成函数)

    最初系数/i!是好算,最后要乘回来

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    using std::vector;
    const int maxn = 1e6 + 20;
    const int mod = 1004535809;
    int len, r[maxn];
    LL ksm(LL x, LL y) {
    	LL re = 1LL;
    	while(y) {
    		if(y & 1) re = re * x % mod;
    		x = x * x % mod;
    		y >>= 1;
    	}
    	return re;
    }
    void FNTT(vector<int> &A, int flag) {
    	A.resize(len);
    	for(int i = 0; i < len; i++) if(i < r[i]) std::swap(A[i], A[r[i]]);
    	for(int l = 1; l < len; l <<= 1) {
    		int w0 = ksm(3, (mod - 1) / (l << 1));
    		for(int i = 0; i < len; i += (l << 1)) {
    			int w = 1, a0 = i, a1 = i + l;
    			for(int k = 0; k < l; k++, a0++, a1++, w = 1LL * w0 * w % mod) {
    				int tmp = 1LL * A[a1] * w % mod;
    				A[a1] = ((A[a0] - tmp) % mod + mod) % mod;
    				A[a0] = (A[a0] + tmp) % mod;
    			}
    		}
    	}
    	if(!(~flag)) {
    		std::reverse(A.begin() + 1, A.end());
    		int inv = ksm(len, mod - 2);
    		for(int i = 0; i < len; i++) A[i] = 1LL * A[i] * inv % mod;
    	}
    }
    vector<int> operator * (vector<int> A, vector<int> B) {
    	int tot = A.size() + B.size() - 1;
    	for(len = 1; len <= tot; len <<= 1);
    	for(int i = 0; i < len; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) * (len >> 1));
    	FNTT(A, 1), FNTT(B, 1);
    	vector<int> ans;
    	for(int i = 0; i < len; i++) ans.push_back(1LL * A[i] * B[i] % mod);
    	FNTT(ans, -1);
    	ans.resize(tot);
    	return ans;
    }
    vector<int> operator - (const vector<int> &A, const vector<int> &B) {
    	vector<int> ans;
    	for(int i = 0; i < (int)std::min(A.size(), B.size()); i++) ans.push_back(A[i] - B[i]);
    	for(int i = B.size(); i < (int)A.size(); i++) ans.push_back(A[i]);
    	for(int i = A.size(); i < (int)B.size(); i++) ans.push_back(-B[i]);
    	return ans;
    }
    vector<int> inv(const vector<int> &A) {
    	if(A.size() == 1) {
    		vector<int> ans;
    		ans.push_back(ksm(A[0], mod - 2));
    		return ans;
    	}
    	int n = A.size(), _ = (n + 1) >> 1;
    	vector<int> B = A, ans;
    	B.resize(_);
    	B = inv(B);
    	ans.push_back(2);
    	ans = B * (ans - A * B);
    	ans.resize(n);
    	return ans;
    }
    vector<int> getd(const vector<int> &A) {
    	vector<int> ans;
    	ans.resize(A.size() - 1);
    	for(int i = 1; i < (int)A.size(); i++) ans[i - 1] = 1LL * i * A[i] % mod;
    	return ans;
    }
    vector<int> geti(const vector<int> &A) {
    	vector<int> ans;
    	ans.resize(A.size() + 1);
    	for(int i = 1; i < (int)ans.size(); i++) ans[i] = 1LL * A[i - 1] * ksm(i, mod - 2) % mod;
    	return ans;
    }
    vector<int> ln(const vector<int> &A) {
    	vector<int> B = getd(A), C = inv(A);
    	return geti(B * C);
    }
    int main() {
    	int n = in();
    	vector<int> a;
    	static int fac[maxn];
    	fac[0] = 1;
    	for(int i = 1; i <= n; i++) fac[i] = 1LL * fac[i - 1] * i % mod;
    	for(int i = 0; i <= n; i++) a.push_back(1LL * ksm(2, (((LL)i * (i - 1)) / 2)) * ksm(fac[i], mod - 2) % mod);
    	a = ln(a);
    	printf("%d
    ", (int)(1LL * a[n] * fac[n] % mod));
    	return 0;
    
    }
    
  • 相关阅读:
    说说 共量子规律
    《【百年美文】原子核中无介子的理由》 回复
    新一代物理课题 : 奶油 为什么 可以 打发 ?
    大自然 的 密码 揭开 后 需要的是 枝繁叶茂 的 计算机 自动控制 系统工程
    签的空白合同有效吗
    css布局单位
    如何计算毛利额和毛利率? 毛利额与毛利率的区别是什么?
    python 练习题 409. 最长回文串
    python 练习题 976. 三角形的最大周长
    VirtualBox 导入之前建的虚拟机
  • 原文地址:https://www.cnblogs.com/olinr/p/10288771.html
Copyright © 2020-2023  润新知