bzoj 2786 DP】的更多相关文章

我们可以将=左右的两个数看成一个块,块内无顺序要求,把<分隔的看成两个块,那么我们设w[i][j]代表将i个元素分成j个块的方案数,那么显然w[i][j]=w[i-1][j]*j+w[i-1][j-1]*j,前面的代表可以将当前元素放到之前j个块中,有j种情况,后面的表示将i元素单独成块之后有j个位置可以选择.需要注意的是我们还需要写高精. 考虑到n比较小,打个表就好了. /*************************************************************…
LINK 题意:给出n,k,有a,b两种值,a和b间互相配对,求$a>b$的配对组数-b>a的配对组数恰好等于k的情况有多少种. 思路:粗看会想这是道容斥组合题,但关键在于如何得到每个a[i]大于b的组数. 不妨从整体去考虑,使用$f[n][j]$代表前n个中有j组$a[i]>b[i]$,很容易得到转移式$f[n][j]=f[n-1][j]+f[n-1][j-1]*(cnt[n]-(j-1))$,其中$cnt[i]$为比a[i]小的b[]个数 但是仔细思考该式子含义会发现,$f[n][j…
这道题被马老板毒瘤了一下,TLE到怀疑人生 //然而BZOJ上妥妥地过了(5500ms+ -> 400ms+) 要么SPFA太玄学要么是初始化block被卡到O(n^4) 不管了,不改了 另外DP方程值得学习 #include<bits/stdc++.h> #define rep(i,j,k) for(int i=j;i<=k;i++) using namespace std; const int maxn = 4e4+11; typedef long long ll; const…
题意:求逆序对数量为k的长度为n的排列的个数 SOL: 显然我们可以对最后一位数字进行讨论,判断其已经产生多少逆序对数量,然后对于前n-1位同样考虑---->每一个长度的排列我们都可以看做是相同的,因为它与最后一位的影响我们已经计算过了.那么就变成了一个好多维DP的过程... 不过我的方程感觉有点太直白,应该可以优化因为在BZ上都是卡时过去的...太慢了...大概状态还是有问题.... Code: /*===============================================…
首先对于一棵树我们可以tree_dp来解决这个问题,那么对于环上每个点为根的树我们可以求出这个树的一端为根的最长链,并且在tree_dp的过程中更新答案.那么我们对于环,从某个点断开,破环为链,然后再用DP来解决这个问题. 备注:很久之前的一道题,刚转的c++,然后T了,也懒得改了. /************************************************************** Problem: 1791 User: BLADEVIL Language: C++…
就是dp啊 f[i][j]表示到第i位,最后一位高度是j的最小花费 转移::f[i][j]=minn(f[i-1][k])+abs(a[i]-num[j]);(k<=j) #include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<queue> using namespace std; int…
打一次鼹鼠必然是从曾经的某一次打鼹鼠转移过来的 以打每一个鼹鼠时的最优解为DP方程 #include<iostream> #include<cstdio> #include<cstdlib> #define N 10005 using namespace std; int n,m,ans; int f[N],t[N],x[N],y[N],mx[N]; int main() { scanf("%d%d",&n,&m); for(int…
思路:dp[ i ][ 0 ]表示第一个是山谷的方案,dp[ i ][ 1 ]表示第一个是山峰的方案, 我们算dp[ x ][ state ]的时候枚举 x 的位置 x 肯定是山峰, 然后就用组合数算方案就好啦. 卡空间 模数是1e9 不是 109 巨坑. #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PII pair<…
最普通dp要4维,因为肯定有一个在上一个的位置,所以可以变为3维,然后滚动数组优化一下. #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PII pair<int, int> #define PLI pair<LL, int> #define ull unsigned long long using n…
思路:很容易写出dp方程,很容易看出能用单调队列优化.. #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PII pair<int, int> #define y1 skldjfskldjg #define y2 skldfjsklejg using namespace std; + ; const int inf…
原来的DP: dp[i][j]表示长度为i的合法串,并且它的长度为j的后缀是给定串的长度为j的前缀. 转移: i==0 dp[0][0] = 1 dp[0][1~m-1] = 0 i>=1 dp[i][0] = dp[i-1][0]*10-dp[i-1][m-1] dp[i][1] = dp[i-1][0]-(a[m]==a[1])*dp[i-1][m-1] dp[i][2] = dp[i-1][1]-(a[m-1~m]==a[1~2])*dp[i-1][m-1] dp[i][3] = dp[i…
这道题我们可以看成给定两个黑白树,可以修改其中一棵树的颜色,问最少修改多少颜色可以使两棵树同构. 首先我们知道在树的同构中树上最长链中点(如果是偶数的话就是中间两个点)是不变的,我们把这个点叫做树的重心(如果有两个重心bz,by的话我们可以加一个点连接bx,by,将加的这个点看成重心),那么我们可以以树的重心为根来DP. 我们可以处理使x,y为根的子树同构的最小代价,判断树同构的合法性我们可以递归的判断每一个儿子的size来判断,设x,y的子节点sonx,sony,那么假设我们求出了所有sonx…
首先如果我们能处理出来i,j段能不能消掉,这样就可以直接dp转移了,设w[i]为前i为最少剩下多少,那么w[i]=w[j-1] (flag[j][i]). 现在我们来求flag[i][j],首先我们可以把字符串组建立trie然后处理在串L中从left位置开始的所有的flag,那么我们可以在trie上一直往下走,每到一个标记的点就将当前的flag[left][right]设为1,那么这样可以处理出连续可以消掉的字符串,然后就处理对于类似L为abcde,字符串组为ade,bc这样可以先消一个,然后再…
对于每一行做DP预处理,w[i][j]代表这一行前i个刷j次的最大价值,那么w[i][j]=max(w[i][j],w[k][j-1]+sum[k+1][i]),sum[i][j]为i-j段刷一次最多正确刷多少个. 那么我们可以将每一行看做一个物品,对于整体做DP,W[i][j]代表前i行刷j次的最大价值,那么W[i][j]=max(W[i][j],W[i-1][j-k]+w[i][k])k<m,这样就可以了. 反思:枚举k的时候方程写错了,写成W[i-1][k]+w[i][j-k]了. /**…
比较容易看出来是DP,但是如果我们记录每一种颜色还剩多少种的话,消耗的转移的时间复杂度5^15,但是我们考虑到每一种颜色,如果数量相同的话,其实是等效的,所以我们用w[a][b][c][d][e][last]记录还剩下1,2,3,4,5次使用次数的颜色的数量为a,b,c,d,e,上一次我们那的是使用次数剩余为last的颜色,那么这次在剩余last-1次的颜色中,我们只能少拿一次,因为不能拿相同的,这样转移就很容易的表示出来了. 我把存状态的数组都开到20就在0mstle了,改到16就好了,求指导…
首先对于m==1的情况非常容易处理(其实这儿因为边界我错了好久...),直接DP就好了,设f[i][k]为这个矩阵前i个选k个矩阵的最大和,那么f[i][k]=max(f[j][k-1]+sum[j+1][i]),那么对于m==2的时候类似与m=1的时候,设w[i][j][k]为左面的一行前i个中,右面的一行前j个中,一共选k个矩阵能选取得最大矩阵. 那么转移也比较明显,有一下几种转移 w[i][j][k]=max(w[i-1][j][k],w[i][j-1][k])这种情况代表什么都不选. w…
我们可以发现,对于最后队列的一段区间[i,j],不论这一段区间如何插入,除了最后一个插入的对象外,剩下的对后续插入没有影响,这启发我们可以用DP来解决这一问题. w[i][j][0..1]代表区间[i,j],最后一个插入的元素是i(0)或者j(1)的方案数,那么就可以根据判断当前插入元素与上一元素的大小关系很容易的转移了. /************************************************************** Problem: User: BLADEVIL…
这道题可以抽象成两个数列,将一个数列变换为另一个 数列的代价最小 首先我们可以处理出所有的状态代表,对于每个状态 用二进制来表示,代表的是两个数列中的每一项选还是不选 那么答案最多为n1+n2-2,也就是先将第一个数列合成一个数 然后再依次拆成第二个数列,那么假设第一个数列选一些,第二个数 列选一些,这个子问题合法(就是第一个数列的选出的和与第二 个的相等),那么我们就没有必要将这个子问题再与大问题合并,也 就是答案减少了2,这样DP就行了 /**************************…
我们可以先DP预处理出W[I]代表买I的东西,每种钞票的个数 不做限制的方案数,那么对于每一组数据的限制,我们可以知道 W[S-C[I]*(D[I]+1)]C为面值,D为数量,这个代表第I种钞票一定 超了的方案数,那么假设我们用二进制来表示对于四种钞票的限制情况 0000表示都不限制,1000代表第一种必须用超,其余没有限制 我们要求的是都限制的请款 那么根据容斥原理,我们可以知道答案是都不限制的-有奇数个1的情况+偶数个1的情况 dfs处理16种情况就好了 /*****************…
我们用DP来解决这个问题 W[I,J]表示准考证的第I位,和不吉利的数匹配到了第J位的方案数,这个状态的表示也可以看成 当前到第I位了,准考证的后J位是不吉利的数的前J位,的方案数 那么我们最后的ans=ΣW[N,I]  0<=I<=M-1 那么我们考虑怎么转移 假设当前到第I位了,匹配到第J位,也就是W[I,J]的值我们有了,我们可以枚举第I+1位是什么, 然后通过KMP的NEXT数组可以快速的得到当前枚举的位可以匹配到第几位,假设可以匹配到第P位, 那么我们W[I+1,P]+=W[I,J]…
这道题根据群论的基础知识,我们可以转化成将n拆分成若干数,求这些数 的lcm的方案数 先筛下素数表prime 那么我们可以用DP来解决这个问题,用W[I,J]代表I这个数,拆成若干个数, 其中质因数最大的不超过prime[j]的方案数 那么我们可以得到转移W[I,J]:=W[I,J-1]+ΣW[I-prime[j]^k,j-1] (I>=prime[j]) /**************************************************************     Pr…
[Cqoi2014]通配符匹配 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 541  Solved: 235[Submit][Status][Discuss] Description 几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户.最常见的通配符有两个,一个是星号(“”’),可以匹配0个及以上的任意字符:另一个是问号(“?”),可以匹配恰好一个任意字符.现在需要你编写一个程序,对于给定的文件名列表和一个包含通配符的字…
思路: http://www.cnblogs.com/exponent/archive/2011/08/14/2137849.html f[i,i+len]=sum[i,i+len]-min(f[i+1,i+len],f[i,i+len-1]); 但题目把n出到5000,内存卡到64M,二维的状态存不下.. 其实,j这一维可以省掉.我们换个状态表示 f[i,i+len]=sum[i,i+len]-min(f[i+1,i+len],f[i,i+len-1]) 然后循环这样写: for len=1…
思路: 普通的DP很好想吧 f[i][j]+=f[i-1][j*s[k]]  前i个数  mod m=j 的个数 m是质数  模数是质数  这就很有趣了 那么我们就求出来原根  所有的数都取指数 搞出生成函数乘法就变成了加法 快速幂+$NTT$就好了 (注意特判零) //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define i…
思路: 这个DP太神了- 完全没想到 http://blog.csdn.net/geotcbrl/article/details/49663401 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int n;long long f[1005][1005][2],m=7777777; int main(){ scanf("%…
思路: 1.DP f[i][j]表示第i个月的月底 还剩j的容量 转移还是相对比较好想的-- f[i][j+1]=min(f[i][j+1],f[i][j]+d[i]); if(j>=u[i+1])f[i+1][j-u[i+1]]=min(f[i+1][j-u[i+1]],f[i][j]+m*j); else f[i+1][0]=min(f[i+1][0],f[i][j]+d[i+1]*(u[i+1]-j)+m*j); //By SiriusRen #include <cstdio> #…
题面 传送门 分析 容易想到根据点来dp,设dp[i][j]表示到i点路径长度为j的方案数 状态转移方程为dp[i][k]=∑(i,j)∈Edp[j][k−1]" role="presentation" style="position: relative;">dp[i][k]=∑(i,j)∈Edp[j][k−1]dp[i][k]=∑(i,j)∈Edp[j][k−1] 但这样得出的结果是错误的,因为它没有考虑一个点经过多次的情况 因此,我们按边来dp,…
显然序列不能超过sqrt(n),因为最差情况是每个都独立答案为n #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; ; int Next[Maxn],F[Maxn],a[Maxn],B[Maxn],Last[Maxn],n,m,Top; inline int Min(…
用w[i]表示在A中用了i的时间时在B中最少用多长时间,然后转移就可以了. 备注:这个边界不好定义,所以可以每次用一个cur来存储最优值,然后对w[i]赋值就可以了. /************************************************************** Problem: 1222 User: BLADEVIL Language: C++ Result: Accepted Time:2648 ms Memory:992 kb ***************…
w[i,j]代表高度j,第i颗树的时候的最大值 那么w[i,j]:=max(w[i,j+1],w[k,j+heigh])+sum[i,j]: 但是这样枚举是n^3的,我们发现转移的第二个选择w[k,j+heigh]与当前 第I颗树没有关系,所以记录一个高度为H的时候时的最大值直接O(1)转移就行了 我也不知道咋回事儿,pascal一直RE,一年前能A的代码现在还是RE,然后向管理员 联系了下,他们说数据没有问题,还把数据发过来了,一共5个点,最后一个点的in竟然 30MB...,挂接都挂不了..…