1. 程式人生 > >【2018瀋陽現場賽I】Distance Between Sweethearts

【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; } }