DP已经做完的题目:
bzoj 1587
//f[i][j]表示前i个位置,分了j段的最小值.// f[i][j] = f[l][j - 1] + a[i];// f[i][j] = min(f[l][j - 1] + sum[i] - sum[l - 1],f[i][j]);#include <iostream>#include <cstring>#include <cstdio>using namespace std;const int maxN = 1000 + 7;inline int read() { int x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();} return x * f;}int f[maxN][15];//f[i][j]表示前i个东西分成j段的最小价值.int a[maxN];int sum[maxN][maxN];//sum[i][j]表示把[1,i - 1]移动到i的价值.int pre[maxN];int main() { // freopen("1.in","r",stdin); int n,k; memset(f,0x3f,sizeof(f)); scanf("%d%d",&n,&k); for(int i = n;i >= 1;-- i) scanf("%d",&a[i]); for(int i = 0;i <= n;++ i) pre[i] = pre[i - 1] + a[i]; for(int i = 0;i <= n;++ i) for(int j = i + 1;j <= n;++ j) sum[i][j] = sum[i][j - 1] + pre[j - 1] - pre[i - 1]; f[0][0] = 0; for(int i = 1;i <= n;++ i) { int tmp = min(i,k); for(int j = 1;j <= tmp;++ j) { f[i][j] = f[i - 1][j - 1]; for(int l = 0;l < i;++ l) { f[i][j] = min(f[i][j],f[l - 1][j - 1] + sum[l][i]); } } } printf("%d\n", f[n][k]); return 0;}
luogu 1423
#include <iostream>#include <cstring>#include <cstdio>const int maxN = 100 + 7;#define rep(i,x,p) for(int i = x;i <= p;++ i) #define sep(i,x,p) for(int i = x;i >= p;-- i)const int gx[] = {0,0,0,1,-1};const int gy[] = {0,1,-1,0,0};int a[maxN][maxN];int f[maxN][maxN];// f[i][j]表示可以到达i行j列的最大步数int n,m;inline int read() { int x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();} return x * f;}inline int max(int a,int b) {return a > b ? a : b;}int dfs(int x,int y) { if(x < 1 || y < 1 || x > n || y > m) return -1; if(f[x][y] != -1) return f[x][y]; int tmp = 0; rep(i,1,4) if(a[x + gx[i]][y + gy[i]] < a[x][y])tmp = max( dfs(x + gx[i],y + gy[i]) + 1, tmp) ; f[x][y] = tmp; return tmp;}int main() { // freopen("1.in","r",stdin); n = read();m = read(); memset(f,-1,sizeof(f)); rep(i,1,n) rep(j,1,m) a[i][j] = read(); rep(i,1,n) rep(j,1,m) if(f[i][j] == -1) f[i][j] = dfs(i,j); int maxx = 0; rep(i,1,n) rep(j,1,n) maxx = max(maxx,f[i][j] + 1); printf("%d\n", maxx); return 0;}
bzoj 3208
#include <iostream>#include <cstdio>#define rep(i,x,p) for(int i = x;i <= p;++ i)#define sep(i,x,p) for(int i = x;i >= p;-- i)const int maxN = 700 + 7;const int gx[] = {0,0,0,1,-1};const int gy[] = {0,1,-1,0,0};int a[maxN][maxN],n,m,f[maxN][maxN];bool vis[maxN][maxN]; //是否可以移动到这...char s[2];inline int read() { int x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();} return x * f;}inline int max(int a,int b) {return a > b ? a : b;}inline int min(int a,int b) {return a > b ? b : a;}void work_1() { int x,y,z; x = read();y = read();z = read(); a[x][y] = z; return;}void work_2() { int x1 = read(),y1 = read(),x2 = read(),y2 = read(); rep(i,x1,x2) rep(j,y1,y2) vis[i][j] = true; return;}void work_3() { int x1 = read(),y1 = read(),x2 = read(),y2 = read(); rep(i,x1,x2) rep(j,y1,y2) vis[i][j] = false;}int dfs(int x,int y) { if(x < 1 || y < 1 || x > n || y > n || vis[x][y]) return -1; if(f[x][y] != -1) return f[x][y]; int tmp = 0; rep(i,1,4) if(a[x + gx[i]][y + gy[i]] < a[x][y])tmp = max( dfs(x + gx[i],y + gy[i]) + 1, tmp) ; f[x][y] = tmp; return tmp;}void work_4() { rep(i,1,n) rep(j,1,n) f[i][j] = -1; rep(i,1,n) rep(j,1,n) if(f[i][j] == -1) f[i][j] = dfs(i,j); int maxx = 0; rep(i,1,n) rep(j,1,n) maxx = max(maxx,f[i][j] + 1); printf("%d\n", maxx);}int main(){ n = read(); rep(i,1,n) rep(j,1,n) a[i][j] = read(); m = read(); while(m --) { scanf("%s",&s); if(s[0] == 'C') work_1(); if(s[0] == 'S') work_2(); if(s[0] == 'B') work_3(); if(s[0] == 'Q') work_4(); } return 0;}/*并给出m个命令,C a b c表示坐标为a,b的点的高度改为c;S a b c d表示左上角为a,b右下角为c,d的矩形地区开始进行保护,即不能继续滑雪;B a b c d表示左上角为a b,右下角为c d的矩形地区取消保护,即可以开始滑雪;Q表示询问现在该风景区可以滑雪的最长路径为多少。对于每个Q要作一次回答。*/
bzoj 1596
#include <iostream>#include <cstdio>#define rep(i,x,p) for(int i = x;i <= p;++ i) #define sep(i,x,p) for(int i = x;i >= p;-- i) const int maxN = 10000 + 7;const int inf = 0x3f3f3f3f;using namespace std;inline int read() { int x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();} return x * f;}int f[maxN][3]; struct Node{ int v,nex;}Map[maxN << 1];int num,head[maxN];inline void add_Node(int u,int v) { Map[++ num].v = v; Map[num].nex = head[u]; head[u] = num;}void dfs(int now,int fa) { bool flag = false; for(int i = head[now];i;i = Map[i].nex) { int v = Map[i].v; if(v == fa) continue; dfs(v,now); flag = true; } if(flag == false) { f[now][0] = inf; f[now][1] = 1; f[now][2] = 0; return; } f[now][1] = 1; int tmp_min = inf; bool is_ok = true; for(int i = head[now];i;i = Map[i].nex) { int v = Map[i].v; if(v == fa) continue; f[now][1] += min(f[v][1] , min ( f[v][0] , f[v][2] ) ); f[now][2] += min( f[v][0] , f[v][1] ); tmp_min = min( f[v][1] - f[v][0] , tmp_min); if(f[v][1] <= f[v][0]) { is_ok = false; f[now][0] += f[v][1]; } else f[now][0] += f[v][0]; } if(is_ok) f[now][0] += tmp_min; return ;}int main(){ // freopen("1.in","r",stdin); int n,u,v; n = read(); for(int i = 1;i < n;++ i){ u = read();v = read(); add_Node(u,v); add_Node(v,u); } dfs(1,1); printf("%d\n", min(f[1][0] , f[1][1])); return 0;}//f[i][0]表示以i为根的子树,最少建造的无线电个数,i点被其儿子覆盖//f[i][1]表示以i为根的子树,最少建造的无线电个数,i点被自己覆盖//f[i][2]表示以i为根的子树,最少建造的无线电个数,i点被其父亲覆盖//f[i][0] = min( )//转移方程://f[i][0] += f[v][0] , f[v][1] ) ;//一定要有一个.这个真麻烦....无语...莫名无语...//f[i][1] += min (f[v][2] , f[v][0], f[v][1]) + 1;//f[i][2] += min ( f[v][0], f[v][1] );
Bzoj 1827
#include <iostream>#include <cstdio>#include <cstring>#define rep(i,x,p) for(re int i = x;i <= p;++ i) #define sep(i,x,p) for(re int i = x;i >= p;-- i)using namespace std;#define ll long long#define re registerconst int maxN = 100000 + 7;struct Node { int v,nex; int w;}Map[maxN << 1];int num,head[maxN];inline int read() { int x = 0 ,f = 1;char c = getchar(); while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();} return x * f;}inline void add_Node(int u,int v,int w) { Map[++ num] = (Node) {v,head[u],w}; head[u] = num; return;}ll f[maxN];ll D[maxN]; ll Q[maxN]; // f[v] = f[u] + (sum - 2 * D[i]) * w[i];// D[u] = \sum D[v] + c[u]// Q[u] = \sum Q[v] + \sum( D[v] * w[i])void dfs_1(int now,int fa) { for(int i = head[now];i;i = Map[i].nex) { int v = Map[i].v,w = Map[i].w; if(v != fa) { dfs_1(v,now); D[now] += D[v]; Q[now] = Q[now] + Q[v] + D[v] * w; } } return;}void dfs_2(int now,int fa) { for(int i = head[now];i;i = Map[i].nex) { int v = Map[i].v,w = Map[i].w; if(v != fa) { f[v] = f[now] + (D[1] - 2 * D[v]) * w; dfs_2(v,now); } }}int main() {// freopen("1.in","r",stdin); int n = read(),u,v,w; rep(i,1,n) D[i] = read(); rep(i,1,n - 1) { u = read();v = read();w = read(); add_Node(u,v,w); add_Node(v,u,w); } dfs_1(1,1); f[1] = Q[1]; dfs_2(1,1); ll ans = 1e12; rep(i,1,n) ans = min(ans,f[i]); printf("%lld\n", ans); return 0;}
bzoj 1037
#include <iostream>#include <cstdio>const int maxN = 150 + 7;const int maxM = 20 + 7;#define rep(i,x,p) for(int i = x;i <= p;++ i) const int mod = 12345678;int f[303][153][23][23];//f[i][j][l][k]表示前i个人,有j个男生.l表示以i为后缀的男生-女生的最大值,//k表示以i为后缀的女生-男生的最大值,inline int max(int a,int b) {return a > b ? a : b;}int main() { f[0][0][0][0] = 1; int n,m,k; scanf("%d%d%d",&n,&m,&k); rep(i,0,n + m - 1) rep(j,0,n) rep(x,0,k) rep(y,0,k) if(f[i][j][x][y]) { if(j + 1 <= n && x + 1 <= k) f[i + 1][j + 1][x + 1][max(y - 1,0)] = (f[i + 1][j + 1][x + 1][max(y - 1,0)] + f[i][j][x][y] ) % mod; if(i + 1 - j <= m && y + 1 <= k) f[i + 1][j][max(x - 1,0)][y + 1] = f[i + 1][j][max(x - 1,0)][y + 1] + f[i][j][x][y] % mod; } int ans = 0; rep(i,0,k) rep(j,0,k) ans = (ans + f[n + m][n][i][j]) % mod; printf("%d\n",ans); return 0;}
bzoj 2037
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>using namespace std;const int maxN = 1000 + 7;int f[maxN][maxN][2]; int sum[maxN][maxN],tmp_sum;struct Node { int x,y,w;}Map[maxN];inline int read() { int x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();} return x * f;}bool cmp(Node a,Node b) { return a.x < b.x;}main() { int n,c,id; n = read();c = read(); Map[n + 1].x = c; for(int i = 1;i <= n;++ i) scanf("%d",&Map[i].x); for(int i = 1;i <= n;++ i) scanf("%d",&Map[i].y); for(int i = 1;i <= n;++ i) scanf("%d",&Map[i].w),tmp_sum += Map[i].w; sort(Map + 1,Map + n + 2,cmp); for(int i = 1;i <= n + 1;++ i) { if(c == Map[i].x) id = i; } for(int i = 1;i <= n + 1;++ i) for(int j = i;j <= n + 1;++ j) sum[i][j] = sum[i][j - 1] + Map[j].w; for(int i = 1;i <= n + 1;++ i) for(int j = i;j <= n + 1;++ j) sum[i][j] = tmp_sum - sum[i][j]; memset(f,-0x3f,sizeof(f)); f[id][id][1] = f[id][id][0] = 0; for(int len = 1;len <= n;++ len) { for(int l = 1;l + len <= n + 1;++ l) { int r = l + len; f[l][r][0] = Map[l].y + max( f[l + 1][r][0] - (Map[l + 1].x - Map[l].x) * sum[l + 1][r] ,f[l + 1][r][1] - ( Map[r].x - Map[l].x ) * sum[l + 1][r]); f[l][r][1] = Map[r].y + max( f[l][r - 1][1] - (Map[r].x - Map[r - 1].x) * sum[l][r - 1] ,f[l][r - 1][0] - ( Map[r].x - Map[l].x ) * sum[l][r - 1]); } } printf("%.3lf\n", max(f[1][n + 1][1] , f[1][n + 1][0]) / 1000.0); return 0;}
luogu 1220
#include <iostream>#include <cstring>#include <cstdio>using namespace std;#define int long longconst int maxN = 1000 + 7;int f[maxN][maxN][2]; //f[i][j][k]表示i到j区间关闭路灯的最小功耗 k:0在左边 1在右边.int sum[maxN][maxN],tmp_sum;struct Node { int pos; int w;}Map[maxN];inline int read() { int x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();} return x * f;}main() { int n,c; n = read();c = read(); for(int i = 1;i <= n;++ i) scanf("%d%lld",&Map[i].pos,&Map[i].w),tmp_sum += Map[i].w; for(int i = 1;i <= n;++ i) for(int j = i;j <= n;++ j) sum[i][j] = sum[i][j - 1] + Map[j].w; for(int i = 1;i <= n;++ i) for(int j = i;j <= n;++ j) sum[i][j] = tmp_sum - sum[i][j]; memset(f,1,sizeof(f)); f[c][c][1] = f[c][c][0] = 0; for(int len = 1;len < n;++ len) { for(int l = 1;l + len<= n;++ l) { int r = l + len; f[l][r][0] = min( f[l + 1][r][0] + (Map[l + 1].pos - Map[l].pos) * sum[l + 1][r] ,f[l + 1][r][1] + ( Map[r].pos - Map[l].pos ) * sum[l + 1][r]); f[l][r][1] = min( f[l][r - 1][1] + (Map[r].pos - Map[r - 1].pos) * sum[l][r - 1] ,f[l][r - 1][0] + ( Map[r].pos - Map[l].pos ) * sum[l][r - 1]); } } printf("%lld\n", min(f[1][n][1] , f[1][n][0])); return 0;}
bzoj4033
/*边一侧的黑节点数*另一侧的黑节点数*边权+一侧的白节点数*另一侧的白节点数*边权*/#include <iostream>#include <cstdio>#define rep(i,x,p) for(int i = x;i <= p;++ i) #define sep(i,x,p) for(int i = x;i >= p;-- i)#define int long longconst int maxN = 2000 + 7;struct Node { int v,nex,w;}Map[maxN << 1];int f[maxN][maxN];int head[maxN],num;int size[maxN];inline int read() { int x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();} return x * f;}void add_Node(int u,int v,int w) { Map[++ num] = (Node) {v,head[u],w}; head[u] = num; return;}int n,k;inline int max(int a,int b) {return a > b ? a : b;}int calc(int val,int num,int x)//计算这条边的贡献 { val=val * x * (k - x) + val * (num - x) * (n - k - (num - x)); return val;}void DP(int now,int fa) { size[now] = 1; for(int i = head[now];i;i = Map[i].nex) { int v = Map[i].v; if(v == fa) continue; DP(v,now); sep(j , size[now], 0) { sep(l , size[v], 0) { int tmp = f[now][j] + f[v][l] + calc(Map[i].w,size[v],l); f[now][j + l] = max(f[now][j + l] , tmp); } } size[now] += size[v]; }}#undef int int main() { #define int long long scanf("%lld%lld",&n,&k); int u , v, w; rep(i,1,n - 1) { u = read();v = read();w = read(); add_Node(u,v,w); add_Node(v,u,w); } DP(1,1); printf("%lld\n", f[1][k]); return 0;}
luogu 3174
bzoj 1260
/*卡常记录: 28ms -> 30ms ?????反过来考虑f[i][j]表示i~j被染色的最小次数.分为三种情况考虑:1.l == r f[l][r] = 1;2.s[l] == s[r] f[l][r] = min(f[i + 1][r] , f[l][r - 1])3.不满足上述条件的话.枚举断点即可.*/#include <iostream>#include <cstring>#include <cstring>#include <cstdio>#define rep(i,x,p) for(register int i = x;i <= p;++ i) #define sep(i,x,p) for(register int i = x;i >= p;-- i)const int maxN = 50 + 7;using namespace std;char s[maxN];int f[maxN][maxN];int main() { scanf("%s",s + 1); int n = strlen(s + 1); memset(f,0x3f,sizeof(f)); rep(i,1,n) f[i][i] = 1; rep(len,1,n - 1) { for(register int l = 1;l + len <= n;++ l){ int r = l + len; if(s[l] == s[r]) f[l][r] = min(f[l + 1][r] , f[l][r - 1]); rep(k , l ,r - 1) f[l][r] = min(f[l][k] + f[k + 1][r],f[l][r]); } } printf("%d", f[1][n]); return 0;}