zoukankan      html  css  js  c++  java
  • BZOJ3771 Triple 【NTT + 容斥】

    题目链接

    BZOJ3771

    题解

    做水题放松一下
    先构造(A_i)(x)指数的生成函数(A(x))
    再构造(2A_i)为指数的生成函数(B(x))
    再构造(3A_i)为指数的生成函数(C(x))

    那么只需计算

    [A(x) + frac{A^2(x) - B(x)}{2} + frac{A^{3}(x) - 3(A(x)B(x) - C(x))}{6} ]

    那么(x^i)的系数即为损失价值(i)的方案数

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cls(s) memset(s,0,sizeof(s))
    #define cp pair<int,int>
    #define LL long long int
    using namespace std;
    const int maxn = 800005,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    const LL P = 2281701377ll,G = 3;
    inline LL qpow(LL a,LL b){
    	LL re = 1;
    	for (; b; b >>= 1,a = a * a % P)
    		if (b & 1) re = re * a % P;
    	return re;
    }
    int R[maxn];
    inline void NTT(LL* a,int n,int f){
    	for (int i = 0; i < n; i++) if (i < R[i]) swap(a[i],a[R[i]]);
    	for (int i = 1; i < n; i <<= 1){
    		LL gn = qpow(G,(P - 1) / (i << 1));
    		for (int j = 0; j < n; j += (i << 1)){
    			LL g = 1,x,y;
    			for (int k = 0; k < i; k++,g = g * gn % P){
    				x = a[j + k],y = g * a[j + k + i] % P;
    				a[j + k] = (x + y) % P,a[j + k + i] = ((x - y) % P + P) % P;
    			}
    		}
    	}
    	if (f == 1) return;
    	LL nv = qpow(n,P - 2); reverse(a + 1,a + n);
    	for (int i = 0; i < n; i++) a[i] = a[i] * nv % P;
    }
    LL A[maxn],B[maxn],C[maxn],D[maxn],ans[maxn],val[maxn],N,deg;
    int main(){
    	N = read();
    	REP(i,N){
    		val[i] = read(),ans[val[i]]++;
    		A[val[i]] = 1; deg = max(deg,val[i]);
    	}
    	//2
    	int n = 1,m = deg << 1,L = 0;
    	while (n <= m) n <<= 1,L++;
    	for (int i = 1; i < n; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
    	NTT(A,n,1);
    	for (int i = 0; i < n; i++) A[i] = A[i] * A[i] % P;
    	NTT(A,n,-1);
    	REP(i,N) A[val[i] << 1]--;
    	for (int i = 0; i < n; i++) ans[i] += A[i] >> 1;
    	
    	//3
    	REP(i,N) B[val[i]] = 1;
    	n = 1,m = deg * 3,L = 0;
    	while (n <= m) n <<= 1,L++;
    	for (int i = 1; i < n; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
    	NTT(B,n,1);
    	for (int i = 0; i < n; i++) B[i] = B[i] * B[i] % P * B[i] % P;
    	NTT(B,n,-1);
    	
    	//2 + 1
    	REP(i,N) C[val[i] + val[i]] = 1,D[val[i]] = 1;
    	int nn = 1; L = 0,m = deg * 3;
    	while (nn <= m) nn <<= 1,L++;
    	for (int i = 1; i < nn; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
    	NTT(C,nn,1); NTT(D,nn,1);
    	for (int i = 0; i < nn; i++) C[i] = C[i] * D[i] % P;
    	NTT(C,nn,-1);
    	REP(i,N) C[val[i] * 3]--;
    	for (int i = 0; i < nn; i++) C[i] *= 3;
    	for (int i = 0; i < n; i++) B[i] -= C[i],B[i] /= 6,ans[i] += B[i];
    	
    	for (int i = 0; i <= deg * 3; i++)
    		if (ans[i]) printf("%d %lld
    ",i,ans[i]);
    	return 0;
    }
    
    
  • 相关阅读:
    java实现倒计时
    javaweb启动时启动socket服务端
    二进制数与十六进制数之间如何互相转换
    分组查询最新时间的数据
    javaweb利用钉钉机器人向钉钉群推送消息(解决中文乱码)
    java利用钉钉机器人向钉钉群推送消息
    Java原生操作数据库(不使用框架)
    Mybatis 插入与批量插入以及多参数批量删除
    在spring中直接在类中注入dao
    web自动化测试实战之批量执行测试用例
  • 原文地址:https://www.cnblogs.com/Mychael/p/9193008.html
Copyright © 2011-2022 走看看