【考試題 - sequence】DP
阿新 • • 發佈:2020-08-04
沒有測試資料,但是和正解對拍了 400 多組資料都過了.
手畫一下發現每個數如果變化的話只有 3 種情況:$-1,0,1$.
感性理解的話一個數變小的話對前面更優,對後面更劣.
但是我們發現不可能存在一個數使得該數變小後會導致後面的數也變小.
這是因為如果該數變小的話說明該數和字首最小值已經構成 $max$,而如果後面的數大於當前數的話顯然只需要分析字首最小值和後面的數就行了.
變小的情況這麼分析,變大的情況同理.
令 $f[i][j]$ 表示做到 $i$ 位,字首最小值是原字首最小值+$j$,時間複雜度為 $O(3^2 n)$.
這道題的資料並不好造,因為如果值域過於分散的話答案就是 1.
所以我們可以生成一個長度為 $10^5$ 的陣列,然後陣列中的每個元素的值域為 $[-100,100]$.
這麼造出來的資料效果不錯,答案一般能超過 $10^3.$
程式碼:
#include <cstdio> #include <cstring> #include <algorithm> #define N 1000009 #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; const int con[]={-1,0,1}; const int pri[]={1,0,1}; const int inf=1000000003; int dp[N][3],mi[N],val[N],n; int get(int x) { if(x==-1) return 0; if(x==0) return 1; if(x==1) return 2; return 23; } int main() { // setIO("input"); scanf("%d",&n); mi[0]=inf; int fax=0; for(int i=1;i<=n;++i) { scanf("%d",&val[i]); mi[i]=min(mi[i-1],val[i]); fax=max(fax,val[i]-mi[i]); } // 存好字首最小值. memset(dp,0x3f,sizeof(dp)); dp[0][1]=0; for(int i=1;i<=n;++i) { for(int x=0;x<3;++x) for(int y=0;y<3;++y) { if(val[i]+con[x]-(mi[i-1]+con[y])>=fax) { continue; } int cur=min(mi[i-1]+con[y],val[i]+con[x]); int p=get(cur-mi[i]); dp[i][p]=min(dp[i][p],dp[i-1][y]+pri[x]); } } int ans=inf; for(int i=0;i<3;++i) { ans=min(ans,dp[n][i]); } printf("%d\n",ans); return 0; }
對拍:
#include <bits/stdc++.h> #define N 1000009 using namespace std; int a[N]; void gen() { FILE *fp=fopen("input.in","w"); int n=100000; a[1]=1,a[n]=9; for(int i=2;i<n;++i) { int p=rand()%100; if(p&1) a[i]=-p; else a[i]=p; } fprintf(fp,"%d\n",n); for(int i=1;i<=n;++i) { fprintf(fp,"%d ",a[i]); } fprintf(fp,"\n"); fclose(fp); } void test() { FILE *fp=fopen("input.in","w"); fprintf(fp,"%d %d\n",rand(),rand()); fclose(fp); } int main() { system("g++ a.cpp -o a.exe -g -O2"); system("g++ b.cpp -o b.exe -g -O2"); srand(time(NULL)); rand(); int cnt=0; while(1) { gen(); system("a.exe < input.in > input.out"); system("b.exe < input.in > de.out"); if(system("fc input.out de.out > FC.out")) { printf("WA\n"); exit(0); } else { printf("AC %d\n",++cnt); } } return 0; }