【2018沈阳现场赛I】Distance Between Sweethearts

题意

分析

看似是期望问题,但是没有权重,就是求平均值,而答案要求乘上方案总数,所以 这是一个计数问题

考虑max,若三个绝对值分别为(x,y,z),则max = max(x,y,z)

distance = max ^ Ib ^ (Ib+x) ^ Ab ^ (Ab + y) ^ Gb ^ (Gb + z) 

我们统计出每种Ib^Ig ( |Ib - Ig| ≤ x ) 的方案数,同理其他属性也是,总共产生三个数组

根据乘法原理,我们可以求得 k = Ib ^ (Ib+x) ^ Ab ^ (Ab + y) ^ Gb ^ (Gb + z) 的方案数为∑ (cnt_I[ Ib ^ (Ib+x) ] * cnt_A[Ab ^ (Ab + y)] * cnt_G[Gb ^ (Gb + z)]),这里就可以做异或卷积 

但我们还要统计max,那在max值固定的情况下,也就是x,y,z至少有一个等于一个定值max,这样的方案数如何统计呢?

考虑容斥,令 某一种方案为Ib ,Ig = (Ib+x), Ab  , Ag =(Ab + y) , Gb ,Gg = (Gb + z)  记作 (x,y,z)

如果我们计算出来了x<=max && y<=max && z <=max的方案数A,又计算出了x<max && y<max && z <max 的方案数B , 上述的方案数就等于A - B,

所以可以每次枚举max值的时候,去累加cnt,这样单种元素的绝对值都不超过max

 

btw:为什么我自己以前fwt板子挂了啊 TAT ,借鉴了聚聚的板子

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;


ll IB,AB,GB,IG,AG,GG;
ll cnt[3][2048];
ll a[3][2048];
ll pre[2048];
ull ans;
void csh(){
    memset(cnt,0,sizeof(cnt));
    memset(pre,0,sizeof(pre));
}
void fwt(ll a[],int n,int v) {
    for(int d=1;d<n;d<<=1) {
    for(int m = d<<1,i=0;i<n;i+=m) {
        for(int j=0;j<d;j++){
        ll x = a[i+j],y = a[i+j+d];
        if(v == 1) a[i+j] = (x+y),a[i+j+d] = (x-y);
        else a[i+j] = (x+y)/2,a[i+j+d] = (x-y)/2;
        }
    }
    }
}
int main() {
    ios::sync_with_stdio(false);
    int _,ca=0;cin>>_;
    while(_--) {
    
    cin>>IB>>AB>>GB>>IG>>AG>>GG;
    csh();
    ans=0;
    for(int maxx = 0;maxx <=2000;maxx++) {
    //    cout<<"MAX = "<<maxx<<endl;
        for(int i=0;i<=IB&&i+maxx<=IG;i++) cnt[0][i^(i+maxx)]++;
        if(maxx>0) for(int i=0;i<=IG&&i+maxx<=IB;i++)cnt[0][i^(i+maxx)]++;
        for(int i=0;i<=AB&&i+maxx<=AG;i++) cnt[1][i^(i+maxx)]++;
        if(maxx>0) for(int i=0;i<=AG&&i+maxx<=AB;i++)cnt[1][i^(i+maxx)]++;
        for(int i=0;i<=GB&&i+maxx<=GG;i++) cnt[2][i^(i+maxx)]++;
        if(maxx>0) for(int i=0;i<=GG&&i+maxx<=GB;i++)cnt[2][i^(i+maxx)]++;
        for(int i=0;i<2048;i++) a[0][i] = cnt[0][i],a[1][i] = cnt[1][i],a[2][i]=cnt[2][i];
        fwt(a[0],2048,1);
        fwt(a[1],2048,1);
        fwt(a[2],2048,1);
        for(int i=0;i<2048;i++) {
        a[0][i] = a[0][i] * a[1][i] * a[2][i];
        }
        fwt(a[0],2048,-1);
        for(int i=0;i<2048;i++) {
        ans+=(a[0][i] - pre[i])*(i^maxx);    
        pre[i] = a[0][i];
        }
    }
    cout<<"Case #"<<++ca<<": "<<ans<<endl;
    }
}

 

posted @ 2018-11-21 03:46  Greenty  阅读(652)  评论(0编辑  收藏  举报