[APIO2015]巴厘岛的雕塑[按位贪心+dp]
生活随笔
收集整理的這篇文章主要介紹了
[APIO2015]巴厘岛的雕塑[按位贪心+dp]
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意
給你長度為 \(n\) 的序列,要求分成 \(k\) 段連續非空的區間,求所有區間和的 \(or\) 最小值。
分析
定義 \(f_{i,j}\) 表示前 \(i\) 個點分成 \(j\) 段的最小 \(or\) 是有問題的,因為可能有一位一定在后面出現而某一位沒有必要在后面出現,這時貪心就出現了問題。
考慮按位貪心,假設考慮到了第 \(b\) 位,定義 \(f_{i,j}\) 表示前 \(i\) 個點分成 \(j\) 段且滿足 \(b\) 以上位的限制,第 \(b\) 位為 \(0\) 是否存在方案。如果這一位沒有方法滿足為 \(0\) 就設置成 \(1\).
復雜度 \(O(60*n^3)\)
對于最后一個 \(subtask\) 稍微改一下定義即可,復雜度 \(O(60*n^2)\)。
代碼
#include<bits/stdc++.h> using namespace std; #define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].lst,v=e[i].to) #define rep(i,a,b) for(int i=a;i<=b;++i) #define pb push_back typedef long long LL; inline int gi(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}return x*f; } template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;} template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;} const int N=2004,inf=0x3f3f3f3f; LL s[N]; int A,B,n; namespace task1{int f[N];LL res=0;void solve(){for(int b=60;~b;--b){fill(f+1,f+1+n,inf);f[0]=0;rep(i,1,n)rep(k,0,i-1)if(f[k]!=inf&&( res>>b+1 | (s[i]-s[k]>>b+1)) ==res>>b+1 && !((s[i]-s[k]>>b)&1))Min(f[i],f[k]+1);if(f[n]!=inf&&f[n]<=B) continue;else res|=1ll<<b;}printf("%lld\n",res);} } namespace task2{bool f[N][N];LL res=0;void solve(){for(int b=60;~b;--b){memset(f,0,sizeof f); f[0][0]=1;rep(i,1,n)rep(j,1,i)rep(k,0,i-1){f[i][j]|=(f[k][j-1]&& ( res>>b+1 | (s[i]-s[k]>>b+1)) ==res>>b+1 && !((s[i]-s[k]>>b)&1));}bool fg=0;for(int i=A;i<=B;++i) fg|=f[n][i];if(!fg) res|=1ll<<b;}printf("%lld\n",res);} } int main(){n=gi(),A=gi(),B=gi();rep(i,1,n) s[i]=s[i-1]+gi();if(A==1) task1::solve();else task2::solve();return 0; }轉載于:https://www.cnblogs.com/yqgAKIOI/p/9900181.html
總結
以上是生活随笔為你收集整理的[APIO2015]巴厘岛的雕塑[按位贪心+dp]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot+redis实现分布
- 下一篇: assert.notStrictEqua