【考試題 - sequence】DP

沒有測試數據,但是和正解對拍了 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;     
}

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章