序列取数
題目描述
給定一個長為n的整數序列(n<=1000),由A和B輪流取數(A先取)。每個人可從序列的左端或右端取若干個數(至少一個),但不能兩端都取。所有數都被取走后,兩人分別統計所取數的和作為各自的得分。假設A和B都足夠聰明,都使自己得分盡量高,求A的最終得分。
輸入輸出格式
輸入格式:
第一行,一個正整數T,表示有T組數據。(T<=100)
接著T行,每行第一個數為n,接著n個整數表示給定的序列.
輸出格式:
輸出T行,每行一個整數,表示A的得分。
題解:
這題剛看的時候覺得還挺簡單啊,不就是一個DP么,被刷成了這種難度,是什么鬼,然后看到了n<=1000,嗯,有點難度了,n^3做法過不了。。。但是稍微加點剪枝什么的幾個億開了O2不還是隨便過,然后發現T<=100.。。。出題人有病么,與其把時限開到3s,還不如少幾組數據。。。。于是發現N^3明顯不可做,開始考慮如何優化掉一個n。考慮原來的DP方程,就是f[i][j]=s[i]-s[j-1]-min(d[i-1][j],[i-2][j],d[i-3][j]....d[i][j-2],d[i][j-1],0)。
發現我們可以記錄下來當前左端和右端取的最優方法,即
L[i][j]=min(f[i][j],L[i+1][j]);
R[i][j]=min(f[i][j],R[i][j-1]);
然后使f[i][j]=s[i]-s[j-1]-min(0,L[i+1][j],R[i][j-1])就可以了。
因為這三個都可以通過O1互相遞推出來,于是就省去了一個N
然后發現數據明顯不對頭,明明5個億在開O(2)的情況下竟跑了1700+ms。。。這題數據有毒,,,。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #include <cstdlib> #include <cmath> #include <string> #include <cstring> #include <cstdio> #include <algorithm> #include <queue> #include <set> #include <map> #define re register #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define MAXN 1e5+1 using namespace std; typedef long long ll; typedef unsigned long long ull; #define ms(arr) memset(arr, 0, sizeof(arr)) const int inf = 0x3f3f3f3f; int T,n,maxx,ans,f[1001][1001],L[1001][1001],R[1001][1001],a[200001],s[2001]; inline int read() {int x=0,c=1;char ch=' ';while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();while(ch=='-') c*=-1,ch=getchar();while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();return x*c; } int main() {//freopen("date.in","r",stdin);T=read();while(T--){n=read();for(re int i=1;i<=n;i++){a[i]=read();s[i]=s[i-1]+a[i];f[i][i]=L[i][i]=R[i][i]=a[i];}for(re int l=1;l<=n;l++){for(re int i=1;i<=n-l;i++){int j=i+l,maxx=0;maxx=min(maxx,min(L[i+1][j],R[i][j-1]));f[i][j]=s[j]-s[i-1]-maxx;L[i][j]=min(f[i][j],L[i+1][j]);R[i][j]=min(f[i][j],R[i][j-1]);}}printf("%d\n",f[1][n]);}return 0; }轉載于:https://www.cnblogs.com/victorique/p/8830679.html
總結
- 上一篇: swing JTable 更新数据
- 下一篇: 七牛2018春季校园招聘后端开发工程师笔