jzoj3512-游戏节目【树状数组,双向dfs】
生活随笔
收集整理的這篇文章主要介紹了
jzoj3512-游戏节目【树状数组,双向dfs】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
大意
有n個節目,每個節目對3個東西貢獻不同,要求選擇至少k個讓第一個東西的值最大。求方案數
解題思路
至少k個我們可以計算選擇任何個數的結果減去選擇k個的結果。由于k比較小,我們考慮直接暴搜
數據不是很大,我們可以將節目分成兩段進行搜索所有結果。
然后第一部分計算第1個東西的值減去第2個東西的值ab1iab1i,和減去第3個東西的值ac1iac1i。
第二部分一樣計算ab2iab2i,ac2iac2i。
問題就變成了選擇兩個數ii,jj使得
andand
ac1i?ac2j>0ac1i?ac2j>0
然后我們將兩個中的 abab合在一起進行離散化,之后用一個樹狀數組或權值線段數進行第二部分查詢每個區間內數的個數,這樣就可以 n??log?nnlogn查詢了。
總共時間復雜度
O(217×log??217+1676116)O(217×log217+1676116)
代碼
#include<cstdio> #include<algorithm> #define ll long long #define N 131080*4 #define lobit(x) x&(-x) using namespace std; struct ansnode{ll c,b;bool f; }ans[N]; ll n,k,a[51],b[51],c[51],t,nz; long long sum,tr[N],ans1; void dfs(ll dep,ll w,ll sum1,ll sum2,ll sum3)//暴力處理k以內的結果 {if (w>=k) return;if (w<k) {if (sum1>sum2&&sum1>sum3)ans1++;}for (ll i=dep+1;i<=n;i++) dfs(i,w+1,sum1+a[i],sum2+b[i],sum3+c[i]); } void dfs1(ll dep,ll sum1,ll sum2,ll sum3)//第一部分搜索 {ans[++t].b=sum1-sum2;ans[t].c=sum1-sum3;ans[t].f=0;for (ll i=dep+1;i<=nz;i++) dfs1(i,sum1+a[i],sum2+b[i],sum3+c[i]); } void dfs2(ll dep,ll sum1,ll sum2,ll sum3)//第二部分搜索 {ans[++t].b-=sum1-sum2;ans[t].c-=sum1-sum3;ans[t].f=1;for (ll i=dep+1;i<=n;i++) dfs2(i,sum1+a[i],sum2+b[i],sum3+c[i]); } bool cmp1(ansnode x,ansnode y)//排序 {return x.c<y.c;} bool cmp2(ansnode x,ansnode y) {return x.b<y.b||x.b==y.b;} void change(ll x,ll up)//樹狀數組——修改 {while (x<=up){tr[x]++;x+=lobit(x);} } long long find(ll x)//樹狀數組——查詢 {long long ans=0;while (x>0){ans+=tr[x];x-=lobit(x);}return ans; } int main() {//freopen("show.in","r",stdin);//freopen("show.out","w",stdout);scanf("%lld%lld",&n,&k);nz=n/2;for (ll i=1;i<=n;i++)scanf("%lld",&a[i]);for (ll i=1;i<=n;i++)scanf("%lld",&b[i]);for (ll i=1;i<=n;i++)scanf("%lld",&c[i]);dfs(0,0,0,0,0);//搜索dfs1(0,0,0,0);//第一部分搜索dfs2(nz,0,0,0);//第二部分搜索sort(ans+1,ans+1+t,cmp1);//離散化——排序ans[t+1].c=-2147483647;ll e=1,last=1;for (ll i=2;i<=t+1;i++){if (ans[i].c!=ans[~-i].c)//離散化——去重,標號{for (ll j=last;j<i;j++)ans[j].c=e;e++;last=i;}}e--;sort(ans+1,ans+1+t,cmp2);ll o=0,g;while (o<=t){g=ans[o].b;last=o;while (ans[o].b==g&&o<=t) o++;for (ll i=last;i<o;i++) if (!ans[i].f) sum+=find(~-ans[i].c);//查詢for (ll i=last;i<o;i++) if (ans[i].f) change(ans[i].c,e);//修改}printf("%lld",sum-ans1);//輸出 }總結
以上是生活随笔為你收集整理的jzoj3512-游戏节目【树状数组,双向dfs】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 经典游戏《轩辕剑叁:云和山的彼端》12
- 下一篇: “苹果税”再招监管:荷兰称苹果抽成制度违