APIO2015巴厘島的雕塑——數位DP
阿新 • • 發佈:2018-04-29
判斷 答案 HR mes != www. tdi turn 枚舉
題目:https://www.luogu.org/problemnew/show/P3646
對於A>1,將答案各位全置1,然後從高位到低位改成0判斷是否可行;
用f[i][j]數組代表前i個數分成j組是否可行,轉移是枚舉最後一段的左端點k,然後看看後面整個一段的和能否滿足要求,如果前後都滿足就表示i,j狀態也可行;
對於A=1,可以貪心地認為分組數量越少越好,所以可行性轉化為最優性,省去一維,轉移條件同上,取min即可;
先寫了個WA一半的版本:
#include<iostream> #include<cstdio> #include<cstring> using囧namespace std; typedef long long ll; int n,A,B,len; ll f2[2005],ans,s[2005]; bool f[105][105];//可行性 bool dp1(ll x) { memset(f,0,sizeof f); f[0][0]=1; for(int i=1;i<=n;i++)//前i個數分成j段 <- 前k個數分成j-1段 for(int j=1;j<=i;j++) for(int k=0;k<i;k++)//0 if(((s[i]-s[k])|x)==x)f[i][j]|=f[k][j-1]; for(int i=A;i<=B;i++) if(f[n][i])return 1; return 0; } bool dp2(ll x) { // memset(f2,0x3f,sizeof f2); f2[0]=0; for(int i=1;i<=n;i++) { ll ad=n+1; for(int j=0;j<i;j++)//0 if(((s[i]-s[j])|x)==x)ad=min(ad,f2[j]); f2[i]=ad+1; }return f2[n]<=B; } int main() { scanf("%d%d%d",&n,&A,&B); for(int i=1;i<=n;i++) scanf("%lld",&s[i]); for(int i=1;i<=n;i++) s[i]+=s[i-1]; for(len = 0;(1LL << len) <= s[n];len++);len--;//位數 if(A!=1) { ans=(ll)(1<<(len+1));ans--; for(int k=len;k>=0;k--)//0! { ll tmp=ans-(ll)(1<<k); if(dp1(tmp))ans=tmp; } } else { ans=(ll)(1<<(len+1));ans--; for(int k=len;k>=0;k--) { ll tmp=(ll)ans-(1<<k); if(dp2(tmp))ans=tmp; } } printf("%lld",ans); return 0; }
後來又直接改成別的寫法A的,但還是不太明白原來的寫法為什麽不行,有什麽不同。
代碼如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long ll; int n,A,B,len; ll f2[2005],ans,s[2005]; bool f[105][105];//可行性 ll dp1() { ans=0; for(int t=len;t>=0;t--) { ans+=(1LL<<t)-1; memset(f,0,sizeof f); f[0][0]=1; for(int i=1;i<=n;i++)//前i個數分成j段 <- 前k個數分成j-1段 for(int j=1;j<=i;j++) for(int k=0;k<i;k++)//0 if(((s[i]-s[k])|ans)==ans)f[i][j]|=f[k][j-1]; bool fl=0; for(int i=A;i<=B;i++)fl|=f[n][i]; if(fl)ans-=(1LL<<t)-1; else ans++; } return ans; } ll dp2() { ans=0; for(int t=len;t>=0;t--) { ans+=(1LL<<t)-1; f2[0]=0; for(int i=1;i<=n;i++) { ll ad=n+1; for(int j=0;j<i;j++)//0 if(((s[i]-s[j])|ans)==ans)ad=min(ad,f2[j]); f2[i]=ad+1; } if(f2[n]<=B)ans-=(1LL<<t)-1; else ans++; } return ans; } int main() { scanf("%d%d%d",&n,&A,&B); for(int i=1;i<=n;i++) scanf("%lld",&s[i]); for(int i=1;i<=n;i++) s[i]+=s[i-1]; for(len = 0;(1LL << len) <= s[n];len++);len--;//位數 if(A==1)printf("%lld",dp2()); else printf("%lld",dp1()); return 0; }
APIO2015巴厘島的雕塑——數位DP