zoukankan      html  css  js  c++  java
  • 简单 dp 题选做

    1. USACO 划分选区 redistricting

    题目大意

    牛分为两类,一类叫荷牛(H),一类叫更牛(G)。两种牛一共占地 (n) 块,每块地归一种牛管。定义一个选区是一种牛的当且仅当这个选区中包含的这种牛的地比另外一种牛多。选区最多包含 (k) 块地。请你求出选区属于更牛或不属于任何牛的最小可能数量。
    数据范围:(1leq kleq nleq 3 imes 10^5)

    分析

    考虑 dp。

    定义 (pre_i) 为前 (i) 块地中 H 的数量减去 G 的数量,预处理 (Theta(n))。实际使用时直接调 (pre_i>0) 就能知道前 (n) 块地中是荷牛数量多还是更牛数量多。若比较区间 ([i,j]),则可以直接算 (pre_i-pre_{i-j})。定义 (dp_i) 即为前 (i) 个块地的答案。

    枚举 (jin[1,k]),考虑最后一块选区由几块地组成。所以方程为:

    [dp_i=min_{1leq jleq k}{dp_{i-j}+[pre_i-pre_{i-j}leq 0]} ]

    直接枚举是 (Theta(nk)) 的,由于只有与当前位置的前 (k) 块地与当前位置的答案有关,考虑单调队列或堆优化即可。复杂度 (Theta(n))

    代码

    //priority_queue ver.
    
    #include<bits/stdc++.h>
    #define HohleFeuerwerke using namespace std
    //#pragma GCC optimize(3,"Ofast","-funroll-loops","-fdelete-null-pointer-checks")
    //#pragma GCC target("ssse3","sse3","sse2","sse","avx2","avx")
    #define int long long
    HohleFeuerwerke;
    inline int read(){
    	int s=0,f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) s=s*10+c-'0';
    	return s*f;
    }
    inline void write(int x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>=10) write(x/10);
    	putchar('0'+x%10);
    }
    int n,k;
    const int MAXN=1e6+5;
    char str[MAXN]; int dp[MAXN];
    int pre[MAXN];
    struct node{
    	int pos,dpval;
    	bool operator<(const node &x)const{
    		if(dpval==x.dpval) return pre[pos]>pre[x.pos];
    		else return dpval>x.dpval;
    	}
    };
    priority_queue<node> pq;
    signed main()
    {
    	n=read();k=read(); cin>>str+1;
    	for(int i=1;i<=n;i++){
    		pre[i]=pre[i-1];
    		if(str[i]=='H') pre[i]++;
    		else pre[i]--;
    	}
    	memset(dp,0x7f,sizeof(dp));
    	dp[1]=(pre[1]==0);pq.push({0,0});
    	for(int i=1;i<=n;i++){
    		node tmp=pq.top();
    		while(tmp.pos<i-k) pq.pop(),tmp=pq.top();
    		dp[i]=min(dp[i],tmp.dpval+(pre[i]<=pre[tmp.pos]));
    		pq.push({i,dp[i]});
    	}
    	write(dp[n]); puts("");
    }
    
    //brute force ver.
    
    #include<bits/stdc++.h>
    #define HohleFeuerwerke using namespace std
    //#pragma GCC optimize(3,"Ofast","-funroll-loops","-fdelete-null-pointer-checks")
    //#pragma GCC target("ssse3","sse3","sse2","sse","avx2","avx")
    #define int long long
    HohleFeuerwerke;
    inline int read(){
    	int s=0,f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) s=s*10+c-'0';
    	return s*f;
    }
    inline void write(int x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>=10) write(x/10);
    	putchar('0'+x%10);
    }
    const int MAXN=1e6+5;
    char str[MAXN];
    int pre[MAXN],n,k; int dp[MAXN];
    signed main()
    {
    	n=read(),k=read();
    	cin>>str+1;
    	for(int i=1;i<=n;i++){
    		pre[i]=pre[i-1];
    		if(str[i]=='H') pre[i]++;
    		else pre[i]--;
    	}
    	memset(dp,0x7f7f,sizeof(dp));
    	dp[1]=(pre[1]==0);
    	for(int i=1;i<=n;i++)
    		for(int j=i-1;j>=i-k&&j>=0;j--){
    			dp[i]=min(dp[i],dp[j]+(pre[i]<=pre[j]));
    		}
    	write(dp[n]); puts("");
    }
    

    2. [POI2008] STA-Station

    题目大意

    给定一棵 (n) 个节点的无根树,求一个节点 (x)(s.t.) 这棵树以 (x) 为根时所有节点深度之和最小。
    数据范围 (1leq nleq 10^6)

    分析

    最简单的做法必然是每个节点为根跑一遍。复杂度 (Theta(n^2))

    我们发现以一个节点为根的答案与其子树大小与父亲节点答案有关。考虑 (dp)

    直接跑一遍必然只能算一个点的答案。所以跑第二遍。实际上就是换根 dp。

    第一遍预处理出一个根的答案,这里以 (1) 举例。第二遍跑的时候就可以通过父节点(这里是以 (1) 为根的时候的父节点)和预处理的 size 来转移就行力。

    考虑节点 (v) 和父亲 (u),那么有:

    [dp_v=dp_u-2sz_v+n ]

    这里需要注意的是只要一个节点 (x) 做了根,在原树中为 (x) 子树的必然贡献 (-1),其余贡献必然 (+1),这样的话 (Delta=-sz_u+(n-sz_u)=n-2sz_u)

    这样复杂度降到 (Theta(n))

    代码

    #include<bits/stdc++.h>
    #define HohleFeuerwerke using namespace std
    #pragma GCC optimize(3,"Ofast","-funroll-loops","-fdelete-null-pointer-checks")
    #pragma GCC target("ssse3","sse3","sse2","sse","avx2","avx")
    #define int long long
    HohleFeuerwerke;
    inline int read(){
    	int s=0,f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) s=s*10+c-'0';
    	return s*f;
    }
    inline void write(int x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>=10) write(x/10);
    	putchar('0'+x%10);
    }
    const int MAXN=1e6+5;
    struct edge{
    	int from,to,next;
    }e[MAXN*2];
    int n,head[MAXN],cntEdge,sz[MAXN],dep[MAXN],dp[MAXN],maxdp,ans;
    inline void add(int u,int v){
    	cntEdge++;
    	e[cntEdge].from=u,e[cntEdge].to=v;
    	e[cntEdge].next=head[u],head[u]=cntEdge;
    }
    inline void dfs1(int u,int fa){
    	sz[u]=1; dep[u]=dep[fa]+1;
    	for(int i=head[u];i;i=e[i].next){
    		int v=e[i].to; if(v==fa) continue;
    		dfs1(v,u); sz[u]+=sz[v];
    	}
    }
    inline void dfs2(int u,int fa){
    	for(int i=head[u];i;i=e[i].next){
    		int v=e[i].to; if(v==fa) continue;
    		dp[v]=dp[u]-2*sz[v]+n;
    		dfs2(v,u);
    	}
    }
    signed main()
    {
    	n=read();
    	for(int i=1;i<=n-1;i++){
    		int u=read(),v=read();
    		add(u,v); add(v,u);
    	}
    	dfs1(1,0);
    	for(int i=1;i<=n;i++) dp[1]+=dep[i];
    	dfs2(1,0);
    	for(int i=1;i<=n;i++) if(dp[i]>maxdp) maxdp=dp[i],ans=i;
    	write(ans),puts("");
    }
    

    3. CF1324F Maximum White Subtree

    题目大意

    给定一棵 (nleq 2 imes 10^5) 个节点的树,对于每一个节点 (i),求出包含节点 (i) 的一个连通子图,(s.t.) 其中白色节点个数 (-) 黑色节点个数最大化。

    分析

    由于树上的连通子图就是子图,直接考虑 dp。

    同样的,由于一个节点的答案可能包含了其父节点,所以需要换根。

    先钦定 (1) 为根,然后先 dp 一遍。

    由于我需要计算两种节点数量差,所以这里的一个 trick 是白色节点 (col) 标记为 (1),黑色节点标记为 (-1)

    (dpa_u) 表示以 (1) 为根,(u) 的子树内的答案。注意一定包含 (u) 本身

    [dpa_u=col_u+sum_{vin ext{subtree}(u)}max(dpa_v,0) ]

    这里子树只要答案 (>0) 那么计算上就可。

    接下来换根计算最终答案 (dpb)。考虑一个节点 (v) 及其父亲 (u)

    [dpb_v=max(0,dpb_u-max(0,dpa_v))+dpa_u ]

    这里的解释是:对于一个节点 (v),我先计算我的父亲对我的答案是否有用,如果有用的话其贡献应该大于 (0)
    对于我父亲的答案,我先减去与我自身有关的,因为我不再是我父亲的子树,我父亲对我的不能包含原本不是其子树的。
    然后我再加上我自己的贡献,就是我自己最终的答案。

    代码

    #include<bits/stdc++.h>
    #define HohleFeuerwerke using namespace std
    #pragma GCC optimize(3,"Ofast","-funroll-loops","-fdelete-null-pointer-checks")
    #pragma GCC target("ssse3","sse3","sse2","sse","avx2","avx")
    #define int long long
    HohleFeuerwerke;
    inline int read(){
    	int s=0,f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) s=s*10+c-'0';
    	return s*f;
    }
    inline void write(int x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>=10) write(x/10);
    	putchar('0'+x%10);
    }
    const int MAXN=2e5+5;
    struct edge{
    	int from,to,next;
    }e[MAXN*2];
    int n,head[MAXN],cntEdge,col[MAXN],dp1[MAXN],dp2[MAXN];
    inline int max(int x,int y){
    	return x>y?x:y;
    }
    inline void add(int u,int v){
    	cntEdge++;
    	e[cntEdge].from=u,e[cntEdge].to=v;
    	e[cntEdge].next=head[u],head[u]=cntEdge;
    }
    inline void dfs1(int u,int fa){
    	dp1[u]=col[u];
    	for(int i=head[u];i;i=e[i].next){
    		int v=e[i].to; if(v==fa) continue;
    		dfs1(v,u); dp1[u]+=max(dp1[v],0);
    	}
    }
    inline void dfs2(int u,int fa){
    	if(u!=1) dp2[u]=max(dp2[fa]-max(0,dp1[u]),0)+dp1[u];
    	for(int i=head[u];i;i=e[i].next){
    		int v=e[i].to; if(v==fa) continue;
    		dfs2(v,u);
    	}
    }
    signed main()
    {
    	n=read();
    	for(int i=1;i<=n;i++){
    		int a=read();
    		col[i]=(a==0)?-1:1;
    	}
    	for(int i=1;i<=n-1;i++){
    		int u=read(),v=read();
    		add(u,v); add(v,u);
    	}
    	dfs1(1,0); dp2[1]=dp1[1];
    	dfs2(1,0);
    	for(int i=1;i<=n;i++) write(dp2[i]),putchar(' ');
    	puts("");
    }
    

    4. [SCOI2005]互不侵犯

    题目大意

    给定 (n imes n) 的一张棋盘,在上面放置了 (k) 个国王使得国王所在格两两没有公共点(即以国王为中心的九宫格内无其他国王),求合法的方案总数。

    (nleq 9)(kleq n^2)

    分析

    显然的状压 dp。

    状压 dp 的套路是通过位运算快速地枚举每一种合法状态,其实是很暴力的一种 dp。

    进行状压的原理就是我把每一行的状态种类给存下来了事。这里每一行的合法状态很少,可以考虑用每一行的合法状态作为转移参数之一。

    考虑,如果我想做第 (i) 行,并且前 (i) 行已经填入了 (k) 个国王的合法方案数。其与 (i-1) 行有关。

    定义 (F(i,S,t)) 表示第 (i) 行的状态为 (S),前 (i) 行一共填入 (t) 个国王的合法方案数,则:

    [F(i,S,t)underset{operatorname{check}(S,T)=operatorname{true}}{=}sum F(i-1,T,t-x) ]

    其中 (x) 表示第 (i) 行这个状态 (S) 的填入的国王个数。那么暴力的转移即可。

    代码

    #include<bits/stdc++.h>
    #define HohleFeuerwerke using namespace std
    #pragma GCC optimize(3,"Ofast","-funroll-loops","-fdelete-null-pointer-checks")
    #pragma GCC target("ssse3","sse3","sse2","sse","avx2","avx")
    #define int long long
    HohleFeuerwerke;
    inline int read(){
    	int s=0,f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) s=s*10+c-'0';
    	return s*f;
    }
    inline void write(int x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>=10) write(x/10);
    	putchar('0'+x%10);
    }
    const int MAXN=15;
    int n,k,ans,dp[MAXN][MAXN*MAXN][MAXN*MAXN],s[MAXN*MAXN],num[MAXN*MAXN];
    inline bool check(int x,int y){
    	if(s[x]&s[y]) return false;
    	if(s[x]&(s[y]<<1)) return false;
    	if(s[x]&(s[y]>>1)) return false;
    	return true;
    }
    signed main()
    {
    	n=read(),k=read();
    	int tot=0;
    	for(int i=0;i<(1<<n);i++){
    		if(i&(i<<1)) continue;
    		int cnt=0;
    		for(int j=0;j<n;j++) if(i&(1<<j)) cnt++;
    		s[++tot]=i; num[tot]=cnt;
    	}
    	dp[0][1][0]=1;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=tot;j++)
    			for(int a=0;a<=k;a++){
    				if(a>=num[j])
    					for(int t=1;t<=tot;t++)
    						if(check(t,j)) dp[i][j][a]+=dp[i-1][t][a-num[j]];
    			}
    	for(int i=1;i<=tot;i++) ans+=dp[n][i][k];
    	write(ans),puts("");
    }
    

    5. [USACO06NOV]Corn Fields G

    题目大意

    给定一个 (n imes m) 的网格地,其中部分地能够选,标记为 1,其余地不能够选,标记为 0。求选定地中没有相邻的地的选择方案数,对 (10^8) 取模。

    (1leq n,mleq 12)

    分析

    跟上面一题差不多。方程是

    [F(i,S)underset{operatorname{check}(S,T)=operatorname{true}}{=}sum F(i-1,T) ]

    只不过你的 check 多判一下跟地图匹配的就行了。

    代码

    #include<bits/stdc++.h>
    #define HohleFeuerwerke using namespace std
    //#pragma GCC optimize(3,"Ofast","-funroll-loops","-fdelete-null-pointer-checks")
    //#pragma GCC target("ssse3","sse3","sse2","sse","avx2","avx")
    #define int long long
    HohleFeuerwerke;
    inline int read(){
    	int s=0,f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) s=s*10+c-'0';
    	return s*f;
    }
    inline void write(int x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>=10) write(x/10);
    	putchar('0'+x%10);
    }
    const int MAXN=15,MOD=1e8;
    int n,m,a[MAXN][MAXN],dp[MAXN][(1<<MAXN)],ans,s[1<<MAXN],cntState;
    inline bool check(int line,int st,int lst){
    	if(st&lst) return false;
    	for(int i=0;i<m;i++){
    		if((a[line][i+1]==0)&&(st&(1<<i))) return false;
    	}
    	return true;
    }
    signed main()
    {
    	n=read(),m=read();
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++){
    			a[i][j]=read();
    		}
    	for(int i=0;i<(1<<m);i++){
    		if(i&(i<<1)) continue;
    		else s[++cntState]=i;
    	}
    	dp[0][0]=1;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=cntState;j++){
    			for(int k=1;k<=cntState;k++){
    				if(check(i,s[j],s[k]))
    					dp[i][s[j]]+=dp[i-1][s[k]],dp[i][s[j]]%=MOD;
    			}
    		}
    	}
    	for(int i=1;i<=cntState;i++) ans+=dp[n][s[i]],ans%=MOD;
    	write(ans),puts("");
    	return 0;
    }
    

    6. [NOI2001] 炮兵阵地

    题目大意

    给定地图,一个炮兵打的范围是上二下二左二右二,炮兵只能放在特定格子内,求给定图中无冲突的放置方案中放炮兵的最多数量。

    (nleq 100)(mleq 10)

    分析

    状压 dp 的题目难点主要在于判断合法状态。然后这题就是多预处理一个每个状态的选中数量,做一遍 dp 就行了。

    但卡空间就是说,发现每一行只与前两行有关,直接滚动数组就行力。

    代码

    #include<bits/stdc++.h>
    #define HohleFeuerwerke using namespace std
    //#pragma GCC optimize(3,"Ofast","-funroll-loops","-fdelete-null-pointer-checks")
    //#pragma GCC target("ssse3","sse3","sse2","sse","avx2","avx")
    #define int long long
    HohleFeuerwerke;
    inline int read(){
    	int s=0,f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) s=s*10+c-'0';
    	return s*f;
    }
    inline void write(int x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>=10) write(x/10);
    	putchar('0'+x%10);
    }
    const int MAXN=10;
    char a[MAXN*MAXN][MAXN];
    int n,m,ans,cntState,dp[5][1<<MAXN][1<<MAXN],s[1<<MAXN],num[1<<MAXN];
    inline bool check(int line,int cur,int bf1,int bf2){
    	for(int i=0;i<m;i++)
    		if((a[line][i+1]=='H')&&(cur&(1<<i))) return false;
    	if(cur&bf1) return false; if(cur&bf2) return false;
    	return true;
    }
    signed main()
    {
    	n=read(),m=read();
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			cin>>a[i][j];
    	for(int i=0;i<(1<<m);i++){
    		if((i&(i<<1))||(i&(i<<2))) continue;
    		s[++cntState]=i;
    		for(int j=0;j<=m;j++) if(i&(1<<j)) num[cntState]++;
    	}
    	for(int i=1;i<=cntState;i++){
    		bool flag=true;
    		for(int j=0;j<m;j++)
    			if((a[1][j+1]=='H')&&(s[i]&(1<<j))) flag=false;
    		if(flag) dp[1][s[i]][0]=num[i];
    	}
    	for(int i=2;i<=n;i++){
    		for(int j=1;j<=cntState;j++){
    			for(int k=1;k<=cntState;k++){
    				for(int l=1;l<=cntState;l++){
    					if(check(i,s[j],s[k],s[l]))
    						dp[i%3][s[j]][s[k]]=max(dp[(i-1)%3][s[k]][s[l]]+num[j],dp[i%3][s[j]][s[k]]);
    				}
    			}
    		}
    	}
    	for(int i=1;i<=cntState;i++)
    		for(int j=1;j<=cntState;j++)
    			ans=max(ans,dp[n%3][s[i]][s[j]]);
    	write(ans),puts("");
    }
    

    7. [Code+#1]找爸爸

    题目大意

    给定两个由 ATGC 组成的字符串 (s_1)(s_2)。由于两个字符串长度可能不同,你可能需要在其中添加空格使得最终两个字符串长度相等。你需要最大化这两个字符串的匹配值。

    对长度相等的这两个字符串进行逐位匹配,如果某一位上两个字符都不是空格,匹配值需要加上这两个字符所对的匹配值(可能有负数)。如果有长度为 (k) 的连续空格,定义这一段的总匹配值为 (g(k)=-a-(k-1) imes b)

    (|s_1|+|s_2|leq 3 imes 10^3)

    分析

    看上去是个字符串题,实际上是个 dp。(这里原因比较显然,因为匹配的权值是给定的,不能通俗的直接进行运算,不过这个还是比较难想到的。)

    我们定义 (dp_{i,j})(s_1) 匹配到第 (i) 位,(s_2) 匹配到第 (j) 位所得的结果。

    试着写一写:(dp_{i,j}=dp_{i-1,j-1}+d_{s_{1_i},s_{2_j}}),我们发现无法处理(无论是前继位还是这一位的)空格情况。那么再加一维来考虑空格。

    显然,如果在匹配的某一位上 (s_1)(s_2) 同时出现空格,这显然是不优的,原因在于多浪费了 (-a) 或者是 (-b)。所以无论匹配到哪一位,空格的可能性只局限于三种:

    • (s_1) 有空格。
    • (s_2) 有空格。
    • (s_1)(s_2) 都没有空格。

    我们另加一维 (dp_{i,j,k}),让 (kin{0,1,2}),记录这种状态下的空格情况。不妨让 (k=0) 表示都没有空格,(k=1) 表示 (s_1) 有空格,(k=2) 表示 (s_2) 有空格。接着做 dp。

    我们发现那个定义连续空格的 (g) 实际上跟 dp 非常适配。我们只需要找到起始点,(-a),接下来全是 (-b)。而起始点在 dp 中只要与前面的 (k) 不同即可。而连续的情况就是 (k) 相等。那么 dp 方程就很好写了。

    [egin{cases}dp_{i,j,0}=max{dp_{i-1,j-1,0},dp_{i-1,j-1,1},dp_{i-1,j-1,2}}+d_{s_{1_i},s_{2_j}}\dp_{i,j,1}=max{dp_{i,j-1,1}-b,dp_{i,j-1,2}-a,dp_{i,j-1,0}-a}\dp_{i,j,2}=max{dp_{i-1,j,1}-a,dp_{i-1,j,2}-b,dp_{i-1,j,0}-a}end{cases} ]

    这题还有一个坑点就是边界。首先 (forall x>0) 不可能存在 (dp_{x,0,1})(dp_{0,x,2}) 的情况。对于 (dp_{0,x,1})(dp_{x,0,2})(g(x))

    特别地,(dp_{0,0,1})(dp_{0,0,2}) 也都不存在。按序模拟即可。

    代码

    #include<bits/stdc++.h>
    #define HohleFeuerwerke using namespace std
    #define int long long
    HohleFeuerwerke;
    inline int read(){
    	int s=0,f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) s=s*10+c-'0';
    	return s*f;
    }
    inline void write(int x){
    	if(x<0) x=-x,putchar('-');
    	if(x>=10) write(x/10);
    	putchar(x%10+'0');
    }
    const int MAXN=3e3+5;
    char str1[MAXN],str2[MAXN];
    int n,m,A,B,d[5][5],dp[MAXN][MAXN][3];
    map<char,int> t;
    inline int tmax(int a,int b,int c){
    	return max(a,max(b,c));
    }
    signed main()
    {
    	scanf("%s",str1+1),scanf("%s",str2+1);
    	n=strlen(str1+1),m=strlen(str2+1);
    	for(int i=1;i<=4;i++)
    		for(int j=1;j<=4;j++) d[i][j]=read();
    	A=read(),B=read();
    	t['A']=1,t['T']=2,t['G']=3,t['C']=4;
    	for(int i=1;i<=n;i++) dp[i][0][2]=-A-(i-1)*B,dp[i][0][1]=dp[i][0][0]=-0x7f7f7f7f;
    	for(int i=1;i<=m;i++) dp[0][i][1]=-A-(i-1)*B,dp[0][i][2]=dp[0][i][0]=-0x7f7f7f7f;
    	dp[0][0][1]=-0x7f7f7f7f,dp[0][0][2]=-0x7f7f7f7f;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++){
    			int x=t[str1[i]],y=t[str2[j]];
    			dp[i][j][0]=tmax(dp[i-1][j-1][0],dp[i-1][j-1][1],dp[i-1][j-1][2])+d[x][y];
    			dp[i][j][1]=tmax(dp[i][j-1][0]-A,dp[i][j-1][1]-B,dp[i][j-1][2]-A);
    			dp[i][j][2]=tmax(dp[i-1][j][0]-A,dp[i-1][j][1]-A,dp[i-1][j][2]-B);
    		}
    	write(tmax(dp[n][m][0],dp[n][m][1],dp[n][m][2])),puts("");
    	return 0;
    }
    
  • 相关阅读:
    判断用户 是用的电脑还是手机 判断 是安卓还是IOS
    特殊符号
    如何在 ajax 外拿到 ajax 的数据???和ajax的参数
    事件(只有事件 没有其他)
    c3 新特性
    jquery 操作属性[选择器为主]
    按字母排序,sql语句查询法
    ubuntu12.04安装lamp的简单lamp
    Ubuntu 下傻瓜式安装配置lamp环境
    万能HTML编辑框 CuteEditor 使用详解
  • 原文地址:https://www.cnblogs.com/AllWeKnow/p/14732910.html
Copyright © 2011-2022 走看看