bzoj3771 Triple

标签: bzoj
3人阅读 评论(0) 收藏 举报
分类:

Description


我们讲一个悲伤的故事。
从前有一个贫穷的樵夫在河边砍柴。
这时候河里出现了一个水神,夺过了他的斧头,说:
“这把斧头,是不是你的?”
樵夫一看:“是啊是啊!”
水神把斧头扔在一边,又拿起一个东西问:
“这把斧头,是不是你的?”
樵夫看不清楚,但又怕真的是自己的斧头,只好又答:“是啊是啊!”
水神又把手上的东西扔在一边,拿起第三个东西问:
“这把斧头,是不是你的?”
樵夫还是看不清楚,但是他觉得再这样下去他就没法砍柴了。
于是他又一次答:“是啊是啊!真的是!”
水神看着他,哈哈大笑道:
“你看看你现在的样子,真是丑陋!”
之后就消失了。
樵夫觉得很坑爹,他今天不仅没有砍到柴,还丢了一把斧头给那个水神。
于是他准备回家换一把斧头。
回家之后他才发现真正坑爹的事情才刚开始。
水神拿着的的确是他的斧头。
但是不一定是他拿出去的那把,还有可能是水神不知道怎么偷偷从他家里拿走的。
换句话说,水神可能拿走了他的一把,两把或者三把斧头。
樵夫觉得今天真是倒霉透了,但不管怎么样日子还得过。
他想统计他的损失。
樵夫的每一把斧头都有一个价值,不同斧头的价值不同。总损失就是丢掉的斧头价值和。
他想对于每个可能的总损失,计算有几种可能的方案。
注意:如果水神拿走了两把斧头a和b,(a,b)和(b,a)视为一种方案。拿走三把斧头时,(a,b,c),(b,c,a),(c,a,b),(c,b,a),(b,a,c),(a,c,b)视为一种方案。

所有数据满足:Ai<=40000

来自 https://www.lydsy.com/JudgeOnline/problem.php?id=3771

Solution


数据只给出了a的范围,这是在提示我们与n无关用桶做(滑稽
如果没有奇怪的限制可以直接写成卷积上,但是加上了限制就要考虑容斥了
考虑用a记录一把斧头拿一次的价值,b记录一把斧头拿两次的价值,c记录一把斧头拿三次的价值
答案就是a+(a*a-y*2)/2+(a*a*a-a*b*3-c*2)/6,这里的乘号是卷积

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <complex>

typedef std:: complex <double> com;
typedef double db;

const db pi=3.1415926535897932;
const int N=524289;

int rev[N];

com a[N],b[N],c[N],ans[N];

void FFT(com *a,int len,db f) {
    for (int i=0;i<len;i++) if (i<rev[i]) std:: swap(a[i],a[rev[i]]);
    for (int i=1;i<len;i*=2) {
        com wn(cos(pi/i),f*sin(pi/i));
        for (int j=0;j<len;j+=i*2) {
            com w(1,0);
            for (int k=0;k<i;k++) {
                com u=a[j+k],v=a[j+k+i]*w;
                a[j+k]=u+v; a[j+k+i]=u-v;
                w*=wn;
            }
        }
    }
    if (f==-1) for (int i=0;i<len;i++) a[i]/=len;
}

int main(void) {
    int n,max=0; scanf("%d",&n);
    for (int i=1;i<=n;i++) {
        int x; scanf("%d",&x);
        a[x]=1; b[x*2]=1; c[x*3]=1;
        max=std:: max(max,x*3);
    }
    int len,lg; for (len=1,lg=0;len<=max*2;len*=2,lg++);
    for (int i=0;i<len;i++) rev[i]=(rev[i/2]/2)|((i&1)<<(lg-1));
    FFT(a,len,1); FFT(b,len,1); FFT(c,len,1);
    for (int i=0;i<len;i++) ans[i]=a[i]+(a[i]*a[i]-b[i])/2.0+(a[i]*a[i]*a[i]-3.0*a[i]*b[i]+c[i]*2.0)/6.0;
    FFT(ans,len,-1);
    for (int i=0;i<len;i++) if ((int)(0.1+ans[i].real())>0) printf("%d %d\n", i,(int)(0.1+ans[i].real()));
    return 0;
}
查看评论

BZOJ3771 Triple

这真是个悲伤的故事 第一次看完题我笑了半天23333 还有就是要认真读题,题里说河神会拿一个,两个,或三个斧子,这并不是什么象征意义,而是确实只是会拿一个,两个或者三个…… 这样的话我们把生成函...
  • neither_nor
  • neither_nor
  • 2016年05月26日 20:07
  • 868

【bzoj3771】Triple FFT

a表示一个的方案数 b表示取两个相同的 c表示取三个相同的 最终,取一个的是a 取两个的是(a*a-b)/2 取三个的是(a*a*a-3*a*b+2*z)/6 a*a*a用FFT算就可...
  • u012288458
  • u012288458
  • 2016年03月25日 08:05
  • 445

bzoj 3771: Triple (容斥原理+生成函数+FFT)

题目描述传送门题目大意:有价值不同的n个物件,求从中选取1-3件物品,能组成多少种不同的价值,已经每种价值的方案数。题解容斥原理+生成函数+FFT代码#include #include #includ...
  • clover_hxy
  • clover_hxy
  • 2017年04月17日 20:51
  • 214

BZOJ 3771 Triple FFT+容斥原理

BZOJ 3771 Triple FFT+容斥原理
  • wzq_QwQ
  • wzq_QwQ
  • 2015年09月01日 17:29
  • 2368

[BZOJ3771]Triple(生成函数+FFT+容斥原理)

题目描述传送门题目大意:给出n个互不相同的数,问从中选出1/2/3个数,每一个可以组合出的和有多少种方案。题解首先1个的直接统计 将所有的数搞成一个生成函数,做一遍卷积搞出来选2个的答案 但是2个...
  • Clove_unique
  • Clove_unique
  • 2017年04月25日 23:23
  • 499

[BZOJ3771]Triple(FFT+生成函数)

生成函数这东西吧,考场上就算考了ATP估计也不会→_→
  • FromATP
  • FromATP
  • 2017年04月06日 21:38
  • 658

bzoj3771 Triple

FFT+容斥原理
  • AaronGZK
  • AaronGZK
  • 2016年06月02日 00:02
  • 2620

BZOJ3771: Triple

母函数 没听过的可以去baiduhttp://blog.miskcoo.com/2015/04/bzoj-3771#include #include #include #include #inclu...
  • liutian429073576
  • liutian429073576
  • 2016年05月01日 13:43
  • 414

[BZOJ3771]Triple(快速傅里叶变换FFT)

FFT+容斥好题啊
  • CABI_ZGX
  • CABI_ZGX
  • 2017年12月09日 14:18
  • 129

[BZOJ3771][生成函数][FFT][容斥原理]Triple

题意给定n个数,求从其中选1个、2个、3个能得到的权值和的情况及方案数生成函数裸题 刚接触这玩意并不是很能理解,也不是很懂怎么表达……考虑f(i)f(i)表示权值和为i的方案数,那么有f(i)=∑f...
  • Coldef
  • Coldef
  • 2017年02月21日 20:38
  • 279
    个人资料
    持之以恒
    等级:
    访问量: 12万+
    积分: 8090
    排名: 3129
    乱七八糟
    文章分类
    最新评论