1. 程式人生 > 其它 >dp記錄

dp記錄

https://www.luogu.com.cn/training/5011#problems

P1049:

把剩餘量轉換成最大裝多少,然後化為01揹包

CF414B:

清新。先設\(f[i][j]\)表示在\(i\)位置填\(j\)的最大方案數。

for(int i = 2; i <= k; i++){
		for(int j = 1; j <= n; j++){
			for(int kk = 1; kk <= j; kk++){
				if(j % kk == 0){
					dp[i][j] += dp[i-1][kk];
					dp[i][j] %= MOD;	
				}
			}
		}
	}

\(O(n^3)\)會TLE。考慮因為當前數應是前一個數的倍數,因為 kk迴圈可以使用倍數 來減少迴圈。

for(int i = 2; i <= k; i++){
		for(int j = 1; j <= n; j++){
			for(int kk = 1; kk * j <= n; kk++){
				f[i][kk*j] = (f[i][kk * j] + f[i-1][j]) % MOD;
			}
		}
	}

P1586

完全揹包,\(n^2\)預處理,\(O(1)\)查詢

for(int i = 1; i * i <= 32768; i++){
		for(int j = i*i; j <= 32768; j++){
			for(int k = 1; k <= 4; k++){
				dp[j][k] += dp[j-i*i][k-1];
			}
		}
	}

P2426

\(dp[i][j]\)表示第i個數分了j段的最大值
則有\(max(dp[i][k], dp[j-1][k-1] + abs(a[i] - a[j]) * (i-j+1))\)

for(int i = 1; i <= n; i++){
		for(int j = 1; j <= i; j++){ // j ~ i 一段 
			for(int k = 1; k <= j; k++){
				if(i == j)	dp[i][k] = max(dp[i][k], a[i] + dp[i-1][k-1]);
				else dp[i][k] = max(dp[i][k], dp[j-1][k-1] + abs(a[i] - a[j]) * (i-j+1));
			}
		}
	}

跑的飛快,人生第一次進最優解第一頁:https://www.luogu.com.cn/record/list?pid=P2426&orderBy=1&status=&page=1

P1387

wtcl\(if (a[i][j]==1) f[i][j]=min(min(f[i][j-1],f[i-1] [j]),f[i-1][j-1])+1;\)

我本來還想想P2058那樣子

P1681同理

P2513

不會推柿子。。。。好吧是字首和優化DP
https://www.luogu.com.cn/blog/user13091/solution-p2513

P1832

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
#define int long long

int prime[100005];
int f[100004];


signed main(){
	int n;
	cin>>n;
	for(int i = 2; i <= n; i++){
		if(prime[i])	continue;
		for(int j = 1; j * i <= n; j++){
			prime[i*j] = true;
		}
		prime[i] = false;
	}	
	// for(int i = 1; i <= n; i++){
		// if(prime[i])	cout<<i<<' ';
	// }cout<<endl;
	f[0] = 1;
	for(int i = 2; i <= n; i++){
		if(prime[i])	continue;
		for(int j = 0; j + i <= n; j++){
			if(f[j]){
				f[j+i] += f[j];
			}
		}
	}
	cout<<f[n]<<endl;
	return 0;
}