[计数][容斥] LOJ#6065 || BZOJ4927 && 2017 山东一轮集训 Day3. 第一题

xiaoxiao2021-02-28  90

因为要选6根木棒,发现肯定是1,1,2,2或1,1,1,3形式。 可以枚举2和3的部分,然后推一推,容斥容斥就可以了 但是细节贼多

#include <cstdio> #include <iostream> #include <algorithm> #include <vector> using namespace std; const int N=5010,MAX=1e7; typedef long long ll; int n,a[N]; ll num[MAX+10],dnum[MAX+10],vis[MAX+10],ans; vector<int> b; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline void rea(int &x){ char c=nc(); x=0; for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc()); } int main(){ rea(n); for(int i=1;i<=n;i++){ rea(a[i]),num[a[i]]++; if(!vis[a[i]]) b.push_back(a[i]); vis[a[i]]=1; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(a[i]+a[j]<=MAX && a[i]<a[j]) dnum[a[i]+a[j]]++; for(int u : b) if(num[u]>=2){ ll x=1LL*num[u]*(num[u]-1)/2,cur=0; if(u%2==0 && num[u/2]>=4) ans+=x*num[u/2]*(num[u/2]-1)*(num[u/2]-2)*(num[u/2]-3)/24; for(int v : b) if(v<u && num[v]>=2 &&num[u-v]>=2 && v<u-v) cur+=num[v]*(num[v]-1)*num[u-v]*(num[u-v]-1)/4; ans+=x*cur; cur=0; for(int v : b) if(v<u && num[u-v] && v<u-v) ans+=x*cur*num[v]*num[u-v],cur+=num[v]*num[u-v]; if(u%2==0) ans+=x*cur*num[u/2]*(num[u/2]-1)/2; } for(int u : b) if(num[u]>=3){ ll x=1LL*num[u]*(num[u]-1)*(num[u]-2)/6,cur=0; if(u%3==0 && num[u/3]>=3) ans+=x*num[u/3]*(num[u/3]-1)*(num[u/3]-2)/6; for(int v : b) if(v<u){ cur+=1LL*num[v]*dnum[u-v]; if(v+v<u && v+v+v!=u ) cur-=1LL*num[v]*num[v]*num[u-v-v]; } ans+=cur*x/3; for(int v : b) if(v*3!=u && v*2<u) ans+=x*num[v]*(num[v]-1)/2*num[u-v-v]; } printf("%lld\n",ans); return 0; }
转载请注明原文地址: https://www.6miu.com/read-75713.html

最新回复(0)