摘要:/*树的重心求法:两次dfs,第一次dfs处理出每个结点的size,以此求每个结点大儿子的size,第二次dfs将每个结点大儿子的size和余下结点数进行比较,所有结点里两个值之间差值最小的那个点就是重心*/#include #include #include #include #include using namespace std; #define maxn 50005 struct Edg...
阅读全文
摘要:/* 二分搜索出一个01段或10即可 先用n个0确定1的个数num 然后测试区间[l,mid]是否全是0或全是1 如果是,则l=mid,否则r=mid,直到l+1==r 然后再测试l是1还是r是1 如何判定[l,mid]是否全是0或1,将这一段变成1进行询问,如果结果=num+len或者结果=num-len,那么就是全0|1 */ #include using namespace std;...
阅读全文
摘要:见博客https://www.cnblogs.com/zwfymqz/p/8588693.html 题解链接https://blog.csdn.net/ripped/article/details/70543595 本题lazy标记设为[change,add]当一个区间向下传递lazy标记时,由于c
阅读全文
摘要:/* dp[i]表示孤立i结点的费用,二分功率上限w,即dp[i]在选择时不可以选择功率大于w的边 */ #include using namespace std; #define maxn 1050 struct Edge{int to,nxt,w;}edge[maxnx)tmp=1100000; if(v==pre)continue; if(flag[v]=...
阅读全文
摘要:网上题解都是用spfa求1-n路径的,但其实dfs一次就可以了。。
阅读全文
摘要:/* 依赖背包 dp[i][j]表示i结点为根的树选择j个用户时的最大剩余费用 即背包容量是j,价值是最大费用 */ #include #include #include using namespace std; #define maxn 3050 struct Edge{int to,nxt,w;}edge[maxn=0;j--) for(int t=0;t>n>>m...
阅读全文
摘要:/*树形dp换根法*/ #include using namespace std; #define maxn 200005 struct Edge{int to,nxt,flag;}edge[maxn>n; for(int i=1;i>s>>t; addedge(s,t,1); addedge(t,s,0); } root=1; d...
阅读全文
摘要:题解链接:https://blog.csdn.net/shiqi_614/article/details/8105149 用树形dp是超时的,,
阅读全文
摘要:/* 两种做法 1.求出树直径v1,v2,那么有一个性质:任取一点u,树上到u距离最远的点必定是v1或v2 那么可以一次dfs求树v1 第二次求dis1[],求出所有点到v1的距离,同时求出v2 第三次求出dis2[],求出所有点到v2的距离 2.树形dp,dp[u][0|1]表示结点u向下的最大距离和向上的最大距离 dp[u][0]可以直接由子树求出 d...
阅读全文
摘要:#include using namespace std; #define maxn 300 struct Edge{int from,to,nxt,flag;}edge[maxnMax){node=u,Max=dep;} for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(edge[i...
阅读全文
摘要:#include using namespace std; #define maxn 500 struct Edge{int to,nxt;}edge[maxnv; void init(){ memset(head,-1,sizeof head); k=tot=0; } void addedge(int u,int v){ edge[tot].to=v;edge[tot]...
阅读全文
摘要:#include #include #include using namespace std; int mp[600][600],m,n,ans; void work(int i){//以第i行为底的矩阵 int stk[600],w[600]={},h[600]={},top=0;//高度栈,左宽栈 memset(stk,-1,sizeof stk); for(in...
阅读全文
摘要:#include using namespace std; int n,mp[5500][5500]; int judge(int i){ for(int j=1;j>n; char ch;int a; for(int i=1;i>ch; if(ch='0')a=ch-'0'; else a=10+ch-'A'; ...
阅读全文
摘要:/*依赖背包的通常做法就是对于每个结点,先处理处其所有子节点的dp,然后对于当前结点进行分组背包dp即可 还是依赖背包问题,dp[i][j]表示结点i的子树用了j个机器人的搜索代价 边界条件,如果某个结点的子树用了0个机器人,那么搜索这个棵子树的代价是边权和*2 将每个结点子树中的机器人看做物品体积,搜索代价看做价值,求最小价值 */ #include using namespace std;...
阅读全文
摘要:多重背包是某个物品可以选择多次,要把对物品数的枚举放在对w枚举外面 分组背包是某组的物品只能选一个,要把对每组物品的枚举放在对w枚举内侧 依赖背包是多层的分组背包,利用树形结构建立依赖关系,每个结点都可以看做分组背包来做
阅读全文
摘要:参考博客:https://blog.csdn.net/my_sunshine26/article/details/77141398 https://blog.csdn.net/qq_38569113/article/details/78718930 dp[l][r]通常由子区间dp[l][k],dp
阅读全文
摘要:/* dp[l][r]表示将任意串的[l,r]刷成s2样子的最小代价 ans[i]表示将s1的前i位刷成s2的代价 按照区间dp的常用做法,dp[l][r]的状态由dp[l][k],dp[k+1][r]决定 若s2[l]==s2[k],那么在刷k的时候也能刷到l,dp[l][r]=min(dp[l][r],dp[l+1][k]+dp[k+1][r]) 但是有可能所有的s[k]!=s[l],即s2...
阅读全文
摘要:/* 按坐标排序 以餐厅为起点向两边扩展区间 dp[i][j][0]表示送完区间[i,j]的饭后停留在左边的代价 dp[i][j][1]表示送完区间[i,j]的饭后停留在右边的代价 */ #include #include #include #include using namespace std; struct A{int x,v;}p[1050]; int...
阅读全文
摘要:见题解链接https://blog.csdn.net/sdjzping/article/details/19160013
阅读全文
摘要:/* 有点像扫描线 思路:从左到右枚举每个点,枚举到点i时,把所有以i为起点的区间的影响删去 再加上以i-1为结尾的区间的影响 */ #include using namespace std; #define maxn 200005 #define lson l,m,rt>1; build(lson); build(rson); pushup(rt); } void ...
阅读全文
摘要:这题有点多重背包的感觉,但还是用完全背包解决,dp[j]表示凑到j元钱时的最大硬币数,pre[j]是前驱,used[j]是凑到j时第i种硬币的用量 △回溯答案时i-pre[i]就是硬币价值
阅读全文
摘要:#include using namespace std; bool ask(int x,int y){ printf("? %d %d\n",x,y); fflush(stdout); char buf[4]; scanf("%s",buf); return buf[0]=='x'; } int work(){ if(ask(0,1))ret...
阅读全文
摘要:模板题poj3624 01背包+限制条件hdu2546 零点偏移poj2184 第k大背包hdu2639 先排序再背包hdu3466
阅读全文
摘要:/* dp[i]:取第i个方块时最多可以累多高 */ #include using namespace std; struct node{ int x,y,z; bool operatora.y; return x>a.x; } //按照x从大到小排,x相同的话就按y从小到大排 }block[1000]; int dp[1000],tot; int...
阅读全文
摘要:/* dp[i][j]表示取第i个数时分成了j块 要么是将第i个数加入j块中的最后一块,要么是自成一块,加上前面j-1块的和 状态转移方程: dp[i][j]=max(dp[i-1][j]+a[i],max{dp[0][j-1]...dp[i-1][j-1]}) 枚举时j为外层循环,i为内层循环, 用滚动数组压缩j,再记录上一轮的dp[0..i][j]的最大值即可 */ #include ...
阅读全文
摘要:发现很早以前用exkmp做过一次,但是对这题来说只要将两个串翻转一下即可转换成s2的所有前缀出现的问题
阅读全文
摘要:/* 特征值k=m-next[m]就是最小循环节的长度, m%k就是去末尾遗留长度 */ #include #include #include using namespace std; char strs[10005][100]; int r,c,w,h,f[1050],nxt[10005];//r是行,c是列 void kmp_pre1(char *s){//求一行的nxt数组 ...
阅读全文
摘要:next数组的含义:next[i]表示以字符串s的第i个字符为结尾的后缀与s前缀匹配的长度 next数组也可以当做fail数组,即当模式串s[j]与串t[i]不匹配时,只要将j转换到next[j]继续匹配即可 在求s的next数组时,也用同样的原理,当s[j]与s[i]不匹配时,只要将j转换到nex
阅读全文
摘要:#include using namespace std; #define maxn 100005 #define INF 0x3fffffff #define pa pair int n,k,pre[maxn],nxt[maxn],len[maxn]; priority_queue,greater >q; int main(){ scanf("%d%d",&n,&k); i...
阅读全文
摘要:#include #include #include #include #include #include #include using namespace std; int main() { int t; int n,m; int num1[2010]; int num2[2010]; priority_queue,less > big; ...
阅读全文
摘要:/* 遇到求最值,且答案显然具有单调性,即可用二分答案进行判定 那么本题要求最大的平均数,就可以转换成是否存在一个平均数为mid的段 */ #include #include #include #include using namespace std; #define maxn 100005 #define esp 1e-6 int N,L; double a[maxn],b[maxn],...
阅读全文
摘要:这题的树状数组是用来维护区间最大值的!非常神奇 第一次见到这种用法,其实和区间求和也没什么差别
阅读全文
摘要:能够二分判定的前提是能找到一个单调关系,有时候需要将不是单调关系的数据转换成另外的具有单调关系的数据
阅读全文
摘要:定理:对于任意整数a,b存在一堆整数x,y,满足ax+by=gcd(a,b) 当d可以整除c时,一般方程ax+by=c的一组特解求法: 1.求ax+by=d的特解x0,y0 2.ax+by=c的特解为(c/d)x0,(c/d)y0 上述方程的通解:(c/d)x0+k(b/d) ,(c/d)y0-k(
阅读全文
摘要:同余类:对于a∈[0,m-1],集合{a+km}的所有数模m同余,余数都是a,该集合成为一个模m的同余类 完全剩余系:模m的同余类共有m个,这m个同余类构成完全剩余系 简化剩余系:1-m中与m互质的数代表的同余类有φ(m)个,它们构成m的简化剩余系。 简化剩余系关于乘法封闭 证明:a,b与m互质,则
阅读全文
摘要:欧拉函数 φ(n) 定义:[1,N]中与N互质的数的个数 性质:1.[1,n]中与n互质的数的和为 n*φ(n)/2; 2.欧拉函数是积性函数 3.p|n && p*p|n =>φ(n)=φ(n/p)*p; 4.p|n && p*p不能整除n,则φ(n)=φ(n/p)*(p-1); 5.sum{φ(
阅读全文
摘要:这是进阶指南第一版的一道题,书上有个推论错了,,
阅读全文
摘要:定理:gcd(a,b)*lcm(a,b)=a*b; 更相损减术:gcd(a,b)=gcd(b,a-b)=gcd(a,a-b) 欧几里得算法:gcd(a,b)=gcd(b,a mod b) 复杂度O(log(a+b))
阅读全文
摘要:推公式题,详见进阶指南p134 思路大概是:当i在区间[x,k/(k/x)]时,k/i的值都是一样的,那么这一段的值可以用等差数列求和公式做
阅读全文
摘要:/* 将C(n,k)质因数分解,然后约束个数按公式计算 */ #include #include #include #include using namespace std; #define ll long long int v[1000],prime[1000],m,c[200],p[200]; void init(int n){ memset(prime,0,sizeof pr...
阅读全文
摘要:hdu1124求阶乘的尾零 light1138 二分答案,最后不要忘记验证答案,
阅读全文
摘要:还以为能用单调栈做出来,,想了老半天,最后发现模拟一下很好做的 按顺序把字符压栈即可
阅读全文
摘要:绝对是好题,把所有警察局放入队列然后开始广搜,如果碰到了vis过的顶点,但是那条边没有访问过,那么这条边就可以删掉 另外广搜的vis标记是在入队时就打的,,
阅读全文
摘要:一开始以为是个树形dp,特地去学了。。结果是个思维题
阅读全文
摘要:#include #include #include #include using namespace std; #define maxn 200005 struct Edge{ int to,next,c; }edge[maxn<<1]; int dp[maxn],f[maxn],vis[maxn],degree[maxn],head[maxn],tot; void addedge(...
阅读全文
摘要:/* 分组背包+树形dp:以树的深度作为阶段,以节点编号作为一维状态, 思路:首先dp[u][t]表示选择以第u门课为根,选了t门课的最大值, 状态转移方程dp[u][t]=max(所有儿子中凑出t-1门课)+s[u], 那么如何在所有儿子中凑出t-1门课,需要用到分组背包,每个儿子为一组,设v是u的一个儿子,那么第v组背包中有t-1件物品,第j件物品体积为j,价值就是dp[v...
阅读全文
摘要:#include #include #include #include using namespace std; int n,dp[6050][2],flag[6050],h[6050]; vector son[6050]; void dfs(int u){ dp[u][0]=0; dp[u][1]=h[u]; for(int i=0;i<son[u].size();i...
阅读全文
摘要:有点理解了进阶指南上说的”阶段,状态和决策“
阅读全文
摘要:普通的多维背包做不了,需要优化一下 但是没有学优化。。别的方法也是可以做的 省去一个 表示阶段的 i 维度,dp[j]表示面值为j的钱是否被凑出来了,used[j]表示第i种硬币在凑面值为j的时候被用的次数
阅读全文
摘要:/* 给定辩控双方给每个人的打分p[i],d[i], dp[j][k]表示前i个人有j个被选定,选定的人的辩控双方打分差之和是k,此状态下的最大辩控双方和 按01背包做,体积一维是1,体积二维是辩控双方打分差,价值是辩控双方打分和 要求体积一维不得超过m,体积二维在体积一维=m的情况下最小 状态转移方程:dp[j][k]=max(dp[j][k],dp[j-1][k-(a[i]-b[i])]+...
阅读全文
摘要:#include #include #include using namespace std; #define ll long long int t,n,a[25],dp[1050]; int main(){ scanf("%d%d",&n,&t); for(int i=1;i=a[i];j--) dp[j]+=dp[j-a[i]]; pri...
阅读全文
摘要://看题解写的 https://blog.csdn.net/sdfzyhx/article/details/51804748#include using namespace std; #define ll long long struct node{ int id,g; bool operatora.g; } }g[35]; int n,m,b[35][5050],...
阅读全文
摘要:/* 两种做法:一是暴力dp[i][j][k][l] 二是以走的步数k作为阶段, dp[k][i][j]表示走到第k步,第一个人横坐标走到i,第二个人横坐标走到j 可以以此推出第第一个人的坐标为[i,k-i+1],第二个人坐标[j,k-j+1] 状态转移方程 dp[k][i][j]=max(dp[k-1][i][j],dp[k-1][i-1][j],dp[k-1][i][j-1],dp[k...
阅读全文
摘要:还是线性dp,有点感觉了,另外这个问题也可以用滚动数组
阅读全文
摘要:要把一个序列变成一个不严格的单调序列,求最小费用 可以用滚动数组实现,空间省了许多
阅读全文
摘要:LCIS就是最长上升公共子序列,要结合LIS和LCS来求 LIS:f[j]=max(f[i])+1; LCS:f[i,j]=max(f[i-1,j],f[i,j-1]或f[i-1,j-1]+1 那么对于LCIS,定义f[i][j]是以B[j]为结尾的最长公共上升子序列长度, 如果A[i]!=B[j]
阅读全文
摘要:#include #include #include #define ll long long using namespace std; int lim[6]; ll dp[31][31][31][31][31]; int main(){ int n; while(scanf("%d",&n)==1){ memset(lim,0,sizeof lim); ...
阅读全文
摘要:一开始没有思路,以为要判联通块。 其实不是判断联通块,而是判断边是否连在一起,没有连边的点可以忽略不计
阅读全文
摘要://没必要递推sg,直接巴什博奕即可 /* 先手面对[n/2,n/9]必胜,即后手面对n/18必败 同理,后手面对n/18^2必败。。。 那么能否使后手面对n/18^k的局势,在于n/18^k是否在[2,9]内 */ #include using namespace std; int main(){ double n; while(scanf("%lf",&n)==1){ ...
阅读全文