日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

jzoj3512-游戏节目【树状数组,双向dfs】

發布時間:2023/12/3 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jzoj3512-游戏节目【树状数组,双向dfs】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題


大意

有n個節目,每個節目對3個東西貢獻不同,要求選擇至少k個讓第一個東西的值最大。求方案數


解題思路

至少k個我們可以計算選擇任何個數的結果減去選擇k個的結果。由于k比較小,我們考慮直接暴搜
數據不是很大,我們可以將節目分成兩段進行搜索所有結果。
然后第一部分計算第1個東西的值減去第2個東西的值ab1iab1i,和減去第3個東西的值ac1iac1i
第二部分一樣計算ab2iab2i,ac2iac2i
問題就變成了選擇兩個數ii,jj使得

ab1i?ab2j>0ab1i?ab2j>0
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】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。