dp

繁繁的游戏

自闭症网瘾萝莉.ら 提交于 2019-12-03 12:15:17
题目描述 繁繁想和小伙伴们打游戏,游戏在一个山庄进行,这个山庄有N座山,编号为1到N,为了方便大家在不同的山之间移动,繁繁建了一些桥,由于技术的原因,桥连接的两座山的高度差不能超过d,现在已知这些桥,求这个山庄最高的山和最低的山差距最大是多少?数据保证所有山之间都是联通的。 输入 第一个一个数T,表示测试数据数量(T<=5,2<=N<=50,0<=d<=1000) 每组数据第一行两个数N和d 接下来一个N行N列的矩阵,第i行j列为Y表示i和j之间建了一座桥,否则表示没有建保证第i行j列和第j行i列值相同,并且第i行第i列值为N 输出 T行,每行一个答案,若最大值可能为正无穷,输出-1 样例输入 3 3 10 NYN YNY NYN 2 1 NN NN 6 1000 NNYNNN NNYNNN YYNYNN NNYNYY NNNYNN NNNYNN 样例输出 20 -1 3000 提示 第一个样例,1和2之间不能超过d,2和3之间不能超过d,那么最大就是1和2差恰好为d,2和3差恰好为d 对于20%的数据,T<=3,N<=40 对于50%的数据,T<=3 对于100%的数据,T<=5,2<=N<=50,0<=d<=1000 代码 //#pragma GCC optimize(3) #include<iostream> #include<cstdio> #include

leetcode32 最长游戏括号 dp

只愿长相守 提交于 2019-12-03 12:14:46
有一说一,我觉得这题没有到困难级 要保存之前的状态,感觉是很明显的dp 思路和题解一样 class Solution { public: int longestValidParentheses(string s) { int len=s.length(); int ret = 0; int *dp=new int[len]; for(int i=0;i<len;i++) dp[i]=0; for (int i = 1; i < s.length(); i++) { if (s[i] == ')') { if (s[i - 1] == '(') { dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; } else if (i - dp[i - 1] > 0 && s[i - dp[i - 1] - 1] == '(') { dp[i] = dp[i - 1] + ((i - dp[i - 1]-2) >= 0 ? dp[i - dp[i - 1] - 2] : 0) + 2; } ret=max(ret,dp[i]); } } return ret; } }; 然后看了题解,因为只有( H和),只需要用left,right记录即可 扫描两遍的原因是 (() 避免这种情况 class Solution { public: int

codeforces597 div2 F 数位dp

荒凉一梦 提交于 2019-12-03 11:51:49
codeforces597 div2 F 数位dp 题意: 求[L,R]中a&b==0的“对数” 思路: 一个典型的求“对数”的数位dp,对比普通的数位dp,共用一个pos,维护两个limit。剩下的就是“暴搜”了,当然注意去重,因为是求对数就不是简单的 \(ans_{R}-ans_{L-1}\) 了。还有要注意lim的状态也要保存,不然会超时。 代码: #include <bits/stdc++.h> using namespace std; #define X first #define Y second #define PB push_back #define LL long long #define pii pair<int,int> #define MEM(x,y) memset(x,y,sizeof(x)) #define bug(x) cout<<"debug "#x" is "<<x<<endl; #define FIO ios::sync_with_stdio(false); #define ALL(x) x.begin(),x.end() #define LOG 20 const int inf =1e9; const int maxn =3e5+7; const int mod = 1e9+7; LL dp[35][2][2]; LL solve(int L

AGC002F Leftmost Ball

时间秒杀一切 提交于 2019-12-03 10:30:37
题意 \(n\) 个数,每个 \(k\) 个,将 \(n\times k\) 个数随意排列,把每数中的第一个改写为 \(0\) ,求不同序列个数。 $n,k \le 2000 $ 传送门 思路 又是一道神仙 \(dp\) 设 \(dp_{i,j}\) 表示当前已经有了 \(i\) 个 \(0\) ,有 \(j\) 个数已经填完的方案数。 转移分两种: 填入一个 \(0\) : \(dp[i+1][j]+=dp[i][j]\) 任选一个没填完的数填进去:此时还剩下的位置共有 \((n-i)*k+j*(k-1)-1\) 个,需要填的是除了这一位和 \(0\) 共 \(k-2\) 个相同的数,数可以是没填过的 \(n-(i-j)\) 种,所以转移如下 \[dp[i][j-1]+=dp[i][j]*(n-(i-j))*C((n-i)*k+j*(k-1)-1,k-2)\] 发现这样子过不了样例,所以再加上 \(k=1\) 时只有全零一种的特判 代码十分简短 #include <bits/stdc++.h> #define upd(x,y) x=(x+(y)>=mu?x+(y)-mu:x+(y)) const int mu=1000000007,N=2005; int dp[N][N],p[N*N],inv[N*N],n,k; int ksm(int x,int y){ int ans=1;

记忆化dp博弈

纵然是瞬间 提交于 2019-12-03 07:20:22
题:http://poj.org/problem?id=2068 题意: 有两个队伍A,B,每个队伍有N个人,交叉坐。即是A(1,3,5,7.....)B(2,4,6,8....)。告诉你每个mi(1<=i<=2n)。 现在有一堆个数为S的石堆,从第1个人开始拿石头,因为是交叉坐所以也就相当于两队轮流拿石头。注意:第i个人拿石头最少拿1个最多拿mi个,拿完石堆中最后一个石头的输。问:A队有没有必胜策略? 分析: 嗯因为数据都不是很大,我们可以用记忆化搜索来求出整个博弈图。如果后继状态有后手必胜(0)那么该状态为先手必胜(1)。如果后继状态全部为先手必胜(1).那么该点状态为后手必胜(0)。当石堆个数为0的时候状态为先手必胜。也就是图的边界。这样用回溯就可以求出所有状态是先手必胜还是后手必胜。 状态表示为 DP[ i ][ j ] 表示轮到第j个人拿,当前还有 i 个石头。 #include<bits/stdc++.h> using namespace std; const int M=1e4+4; int dp[M][30]; int a[M]; int n; int s; int dfs(int m,int p){ if(p==2*n)///循环重新来 return dfs(m,0); if(dp[m][p]!=-1)///记忆化搜索 return dp[m][p]; if(m=

子树问题(DP)

一个人想着一个人 提交于 2019-12-03 06:43:52
这题显然是DP 首先, \(dp[i][j]\) 表示树深度小于等于i,树的大小为j的有根树的数量$ 可以循环枚举根节点编号次大的子树的大小k。 \(dp[i][j]=\sum^{j-1}_{k=1}dp[i][j-k]*dp[i-1][k]*C^{k-1}_{j-2}\) 注释:第一个dp表示的是除去这棵大小为k的子树的有根树数量,第二个dp表示的是这棵大小为k的子树的有根树数量,最后要给每一个点分配编号,只用分编号给(k的子树)或(除去k的剩余树),所以乘一个 \(C^{k-1}_{j-2}\) 因为一开始设的是深度小于等于i,所以最后要融斥去掉重复的树的数量。 因为一开始没有考虑这种树的好坏,所以当大小j是坏的时候,dp[i][j]=0。 来源: https://www.cnblogs.com/2017gdgzoi44/p/11781020.html

博弈论问题

荒凉一梦 提交于 2019-12-03 06:33:52
对钟长者的课堂总结QwQ 类型一:一人进行一件事回合制游戏(例如取k样东西,走k步) 解题方法:设dp[i][j][k]...(表示状态)表示在此状态是必胜态还是必败态 然后看这个状态可以转移到那几个状态,如果此状态转移到的所有状态均为必胜态 则此状态为必败态,若此状态的所有转移中有一个为必败态,则此状态为必胜态。 例一:有n件物品,Alice和Bob在进行游戏,Alice为先手,对于每回合,Alice和Bob 可以取走2-5件物品,Alice和Bob均使用最优策略,问Alice是必胜还是必败。 设dp[i]表示到第i件物品时是必胜态(true)还是必败态(false)。 由Alice为先手,每回合可以取走2-5件物品可知,dp[1]=false; dp[2]=dp[3]=dp[4]=dp[5]=true; 然后遍可以从6-n进行O(4*n)的转移,检验dp[i-2],dp[i-3],dp[i-4],dp[i-5]的值, 如果四个值均为true,则说明无论这个时候怎么取,他的对手在下一轮一定是必胜态, 所以这个时候是必败态,如果四个值里面有大于等于1个false,则证明此时可以用最优策略 转移到对手的那轮是必败态,所以这个时候是必胜态。 例二: 来源: https://www.cnblogs.com/Hoyoak/p/11780768.html

scrape ASIN from amazon URL using javascript

匿名 (未验证) 提交于 2019-12-03 02:44:02
可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试): 问题: Assuming I have an Amazon product URL like so http://www.amazon.com/Kindle-Wireless-Reading-Display-Generation/dp/B0015T963C/ref=amb_link_86123711_2?pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-1&pf_rd_r=0AY9N5GXRYHCADJP5P0V&pf_rd_t=101&pf_rd_p=500528151&pf_rd_i=507846 How could I scrape just the ASIN using javascript? Thanks! 回答1: Amazon's detail pages can have several forms, so to be thorough you should check for them all. These are all equivalent: http://www.amazon.com/Kindle-Wireless-Reading-Display-Generation/dp/B0015T963C http://www.amazon.com

[SDOI2010]地精部落

点点圈 提交于 2019-12-03 02:23:22
做法:DP+组合数 首先我们定义 \(dp[i]\) 为长度为i时的方案数。 不难想到,如果要满足每一个点都满足为山峰或者山谷的话,肯定是曲折的。(及若山谷为0,山峰为1,肯定是 \(010101010101\cdots\) 或者 \(101010101010\cdots\) ) 我们把这一个长度为n分成两个部分,设左边的长度为j,则右边的长度为i-j 发现这样不太好转移,于是我们把dp的状态再 定义严格一点 。 我们定义 \(dp[i]\) 表示长度为i, 且第一个严格为山峰 的方案书。 那么我们此时此刻,左边的开头与右边的开头就都是山峰了。 由上面的 \(01\) 串可得,我们的左边最后一个也得是山峰,也就是说,我们左边的长度得是 奇数 最后一个问题:如何保证 左边最后一个 与 右边第一个 一定为山峰? 我们把中间放上了一个最小值不就好了吗? 因此我们得到dp转移方程 \(dp[i] = \sum_{j=1}^{i-1} dp[j] * dp[i-1-j]*C_{i-1}^{j}(j\%2==1)\) 然后进行dp就好了。 对于山谷,与山峰的情况是完全一样的,因此我们直接*2即可 Code: #include<bits/stdc++.h> #define re register #define rep(i,a,b) for(re int i=a,i##end=b; i<=i#

leetcode 322. 零钱兑换 java

心不动则不痛 提交于 2019-12-03 02:15:17
题目: 给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。 示例 1: 输入: coins = [1, 2, 5], amount = 11 输出: 3 解释: 11 = 5 + 5 + 1 示例 2: 输入: coins = [2], amount = 3 输出: -1 说明: 你可以认为每种硬币的数量是无限的。 解题: class Solution { public int coinChange(int[] coins, int amount) { if(coins.length == 0) return -1; //声明一个amount+1长度的数组dp,代表各个价值的钱包,第0个钱包可以容纳的总价值为0,其它全部初始化为无穷大 //dp[j]代表当钱包的总价值为j时,所需要的最少硬币的个数 int[] dp = new int[amount+1]; Arrays.fill(dp,1,dp.length,Integer.MAX_VALUE); for (int coin : coins) { for (int j = coin; j <= amount; j++) { if(dp[j-coin] != Integer.MAX_VALUE) { dp[j] =