P5154 數列遊戲(區間dp)
阿新 • • 發佈:2019-01-02
果然和dp有關的東西我絕對做不出來啊……
設\(dp[i][j]\)表示消完區間\([i,j]\)中的數之後能得到的最大分數,如果消不完則為\(-inf\),否則列舉斷點。順便如果\(a[i],a[j]\)不互質可以用\(dp[i+1][j-1]+b[i]+b[j]\)來更新答案
然後設\(f[i]\)為字首的答案,直接普通的dp即可
//minamoto #include<bits/stdc++.h> #define R register #define ll long long #define inf 1e18 #define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i) #define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i) #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v) template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} using namespace std; char buf[1<<21],*p1=buf,*p2=buf; inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;} int read(){ R int res,f=1;R char ch; while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1); for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0'); return res*f; } char sr[1<<21],z[20];int C=-1,Z=0; inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} void print(R int x){ if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]='\n'; } const int N=1005; int gcd(int x,int y){return y?gcd(y,x%y):x;} ll dp[N][N],f[N];int a[N],b[N];int n;bool Gcd[N][N]; int main(){ // freopen("testdata.in","r",stdin); n=read(); fp(i,1,n)a[i]=read(); fp(i,1,n)b[i]=read(); fp(i,1,n)fp(j,i+1,n)Gcd[i][j]=gcd(a[i],a[j])>1?1:0; fp(i,1,n-1)dp[i][i+1]=Gcd[i][i+1]?b[i]+b[i+1]:-inf; fp(j,4,n)if(~j&1)fp(i,1,n-j+1){ dp[i][i+j-1]=-inf; if(Gcd[i][i+j-1])dp[i][i+j-1]=dp[i+1][i+j-2]+b[i]+b[i+j-1]; fp(k,i+1,i+j-2)if((k-i)&1) cmax(dp[i][i+j-1],dp[i][k]+dp[k+1][i+j-1]); }fp(i,2,n){ f[i]=f[i-1]; fp(j,1,i-1)cmax(f[i],f[j-1]+dp[j][i]); }printf("%lld\n",f[n]); return 0; }