zoukankan      html  css  js  c++  java
  • 2019.2.14 考试T1 FFT

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

    衡水二中的机房里经常有人莫名其妙地犇雷,leizi很生气,决定要找出那个犇雷的人

    机房有n个人,每个人都认为机房里有两个人可能会犇雷,其中第i个人认为xi和yi可能会在机房犇雷(1<=i,xi,yi<=n,xi!=yi) (某个人不可能资磁自己犇雷,即xi,yi!=i)

    leizi决定找出两个pwang并把他们按在床上揍。leizi希望选择的方案恰好被c个人支持,一个oier会支持一个方案当且仅当至少有一个他认为的pwang被leizi揍了。

    请对于所有的c∈[0,n]求出leizi选择的方案数。

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

    从leigehhh.in读入

    第一行输入一个整数n

    接下来n行,每行输入两个整数xi和yi中间用空格分开。

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

    将输出写到leigehhh.out

    输出n+1行,第i行代表c=i-1时的方案数

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

    8
    5 6
    5 7
    5 8
    6 2
    2 1
    7 3
    1 3
    1 4
    

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

    0
    0
    1
    12
    10
    4
    1
    0
    0
    

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

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

    对于30%的数据,n<=1000 且 数据随机

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

    你需要提交源文件leigehhh.cpp/c/pas

    本题开启special judge,如果你觉得某个子任务非常难,您可以尝试完成以下任务,并获得本测试点60%的分数:

    第一行输出"IAKNOI"(不包含引号)

    第二行输出对于c∈[n/4,n]的方案数之和,n/4向下取整。

    例如对于样例,可以输出:

    IAKNOI

    28

    本题使用Lemon评测,配置Lemon风格的自定义校验器。

    温馨提示:1.正解不难2.如果不会正解,本题可以使用多种奇怪的方法操到好多分

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

    我们开一个数组,mp[i]记录对每个人有多少人支持i

    (S_{i,j})为同时支持i和j的人数

    那么答案即为(mp[i]+mp[j]-s[i][j])的桶

    不难发现,(s[i][j])只存在n个,而前面存在(n^2)

    考虑算出(mp[i]+mp[j])的桶,然后在桶上修改

    (t[mp[i]+mp[j]]--,t[mp[i]+mp[j]-s[i][j]]++),直接修改

    这个很容易办到

    现在考虑怎么求(mp[i]+mp[j])

    可以列出式子,最后的桶(ans[v]=sum[mp[i]+mp[j]==v])

    这启示我们对mp开桶,设为t

    (egin{aligned} ans[v]=sum_{mp_i+mp_j=v}t_{mp_i}*t_{mp_j}end{aligned})

    这是。。。卷积啊!!

    一波FFT过去,ans就出来了

    但其中有些值不对

    比如(t:1 3 2)

    FFT后4的系数为(1*2+3*3+2*1)

    但实际上我们只有一个3,而且上面有重复

    对于(mp_i=mp_j)的情况,不难发现只有在奇数的时候才会出现

    这时候把平方减去,加上正确的贡献(C_n^2)即可

    还要/2

    最后别忘考虑那些存在s的东西

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cctype>
    #include<vector>
    #include<cmath>
    #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;
    }
    namespace qwq {
    	void in() {
    		freopen("leigehhh.in", "r", stdin);
    		freopen("leigehhh.out", "w", stdout);
    	}
    	void out() {
    		fclose(stdin);
    		fclose(stdout);
    	}
    }
    using std::vector;
    const int maxn = 1e5 + 100;
    const double pi = acos(-1);
    int t[maxn], mp[maxn];
    LL tt[maxn], lst[maxn], ans[maxn];
    vector<int> v[maxn];
    struct node {
    	double x, y;
    	node(double x = 0, double y = 0): x(x), y(y) {}
    	friend node operator + (const node &a, const node &b) { return node(a.x + b.x, a.y + b.y); }
    	friend node operator - (const node &a, const node &b) { return node(a.x - b.x, a.y - b.y); }
    	friend node operator * (const node &a, const node &b) { return node(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); }
    	friend node operator / (const node &a, const double &b) { return node(a.x / b, a.y / b); }
    }A[maxn], B[maxn], C[maxn];
    int len, r[maxn];
    void FFT(node *D, int flag) {
    	for(int i = 0; i < len; i++) if(i < r[i]) std::swap(D[i], D[r[i]]);
    	for(int l = 1; l < len; l <<= 1) {
    		node w0(cos(pi / l), flag * sin(pi / l));
    		for(int i = 0; i < len; i += (l << 1)) {
    			node w(1, 0), *a0 = D + i, *a1 = D + i + l;
    			for(int k = 0; k < l; k++, a0++, a1++, w = w * w0) {
    				node tmp = *a1 * w;
    				*a1 = *a0 - tmp;
    				*a0 = *a0 + tmp;
    			}
    		}
    	}
    	if(!(~flag)) for(int i = 0; i < len; i++) D[i] = D[i] / len;
    }
    int main() {
    	freopen("leigehhh.in", "r", stdin);
    	freopen("leigehhh.out", "w", stdout);
    	int n = in();
    	int x, y;
    	for(int i = 1; i <= n; i++) {
    		x = in(), y = in();
    		v[x].push_back(y);
    		v[y].push_back(x);
    		mp[x]++, mp[y]++;
    	}
    	for(int i = 1; i <= n; i++) {
    		std::sort(v[i].begin(), v[i].end());
    		for(int j = 0; j < (int)v[i].size(); j++) t[v[i][j]]++;
    		for(int j = 0; j < (int)v[i].size(); j++) {
    			if(j && v[i][j] == v[i][j - 1]) continue;
    			ans[mp[i] + mp[v[i][j]]]--;
    			ans[mp[i] + mp[v[i][j]] - t[v[i][j]]]++;
    			t[v[i][j]] = 0;
    		}
    	}
    	for(int i = 1; i <= n; i++) tt[mp[i]]++;
    	for(int i = 0; i <= n; i++) B[i] = A[i] = tt[i];
    	for(len = 1; len <= n + n; len <<= 1);
    	for(int i = 0; i < len; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) * (len >> 1));
    	FFT(A, 1), FFT(B, 1);
    	for(int i = 0; i < len; i++) C[i] = A[i] * B[i];
    	FFT(C, -1);
    	for(int i = 0; i <= n; i++) lst[i] = (int)round(C[i].x); 
    	for(int i = 0; i <= n; i++) {
    		if(i & 1) continue;
    		lst[i] -= tt[i >> 1] * tt[i >> 1];
    		lst[i] += (tt[i >> 1] * (tt[i >> 1] - 1LL));
    	}
    	for(int i = 0; i <= n; i++) printf("%lld
    ", (ans[i] >> 1LL) + (lst[i] >> 1LL));
    	return 0;
    }
    

    一直写vector的NTT,一下子写double的FFT, 数组开小了。。。。(100pts o 30pts)欲哭无泪(雾

  • 相关阅读:
    PCI配置空间与IO空间与内存空间
    python读配置文件,根据配置文件内容改写二进制文件
    python参数的传递机制
    python复制、移动文件到指定文件夹
    python解析配置文件
    python struct用法
    Python 字符串前面加u,r,b的含义
    shell算数运算符
    三、shell -break、continue、exit、return
    shell-逻辑判断
  • 原文地址:https://www.cnblogs.com/olinr/p/10374880.html
Copyright © 2011-2022 走看看