首页 > 其他分享 >做题小结-含做不来的计数DP

做题小结-含做不来的计数DP

时间:2024-07-09 17:54:36浏览次数:18  
标签:这个 int max 30 做不来 range DP 小结 dp

第一个题

首先这个题 我没做出来

我在这里还是要总结下基环树喜欢考什么
我以前做过一个交互题 题目大意忘了
反正考的是基环树最重要的一个性质 两个点之间一定存在两个走法,一个是正常走 另一个是走环

反正就是一定有两条路过来

那这个题就是考虑这个性质
还有就是正常树的 要找到>=1的这个路径很明显 任何两个点之间都行 就是
\(C_n^2\) ,那很明显答案就是那些环上的可以*2 别的其实都是 1 ,于是我们大不了把所有人都认为是2 然后减去不是环的子树就行了 非常巧妙
我们使用tarjan求出那个环 然后对环上的每一个点进行dfs 求得子树 即可 此题是一个很有意思的题目

点击查看代码
#include <bits/stdc++.h>
#define int long long 
#define endl '\n'
//必须写题解 就是基环树的两种走法的那个知识
//写tarjan坏了一定要注意
//是不是 你h数组没有初始化或者又变成0了?(-1)的时候
using namespace std;
#define debug cout<<endl<<"----------"<<endl;
const int range=3e5+100;
int n,m,a,b;
vector<int> v[range]; 
int dfn[range],low[range],tot;
int stk[range],instk[range],top;
int scc[range],siz[range],cnt;	
int ne[range*2];
int h[range*2];
int e[range*2];
int flag;
int idx;
void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
void cclear()
{
	top=0;cnt=0;idx=0;tot=0;
	flag=0;
	for(int i=0;i<=n;i++)h[i]=-1;
	for(int i=1;i<=n;i++)
	{   v[i].clear();
		siz[i]=0;
		instk[i]=ne[i]=e[i]=stk[i]=scc[i]=dfn[i]=low[i]=0;
	}	
}
void tarjan(int x,int fa)
{
	dfn[x]=low[x]=++tot;
	stk[++top]=x;
	for(int i=h[x];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(!dfn[j]){
			tarjan(j,i);
			low[x]=min(low[x],low[j]);
		}
		else if(i!=(fa^1)){
			low[x]=min(low[x],dfn[j]);
		}		
	}
	if(dfn[x]==low[x])
	{
		++cnt;
		int y;
		do{
			y=stk[top--];
			v[cnt].push_back(y);
			scc[y]=cnt;
			++siz[cnt];
		}while(y!=x);
	}
}
int  dfs(int x,int fa)
{
	int g=0;
	g++;
	for(int i=h[x];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(j==fa||scc[j]==flag)continue;
		g+=dfs(j,x);		
	}
	return g;
}
void solve(){
	cin>>n;
	cclear();
	int ans=n*(n-1);
	for(int i=1,x,y;i<=n;i++)
	{
		cin>>x>>y;
		add(x,y);add(y,x);
	}
	for(int i=1; i<=n; i++)
		if(!dfn[i]) tarjan(i,0);
	for(int i=1;i<=cnt;i++)
		if(siz[i]>1) {
			flag=i;break;
		}
	for(auto i:v[flag])
	{  
		int h=dfs(i,0);
		ans-=(h*(h-1)/2);
	}	
	cout<<ans<<endl;
	cclear();
}
signed main()
{
	int t;
	cin>>t;
	while(t--)
		solve();
}

第二题

这题4月做的 重新写了一遍
是一个线性dp的好题 噢,我昨天晚上做了一个计数dp的题目 做了很久 看题解看来一个多小时还是没看懂 于是这题被我扔了

题目

回到这里
这题要怎么写?
首先得明确知道这个只好用dp去写了
如果写呢?
注意到数据1e9 可以发现最多用30把坏钥匙 再用了都是0

我们可以发现可以用二维数组记录钥匙使用数量 进行转移即可 于是朴素得写法就是dp[2e5][30]这样就行 然后转移方程式

max:
dp[i][j]=dp[i-1][j-1]+a[i]>>j
dp[i][j]=dp[i-1][j]+a[i]>>j-k

然后就可以去做了
不过这里其实还是可以优化的 进行降维 让我们回顾一下降维的原则

为什么在01背包逆序可以做到降维呢

因为j是逆序循环的 
所以dp[j]会优先于dp[j-a[i]]更新
也就是说dp[j-a[i]]就相当于dp[i-1][j-a[i]
于是就相当于dp[i-1][j-a[i]+w[i]  

相当于用上一行的dp[j-w[i]]去更新dp[j]

dp[i][j]=max(dp[i-1][j],dp[i-1][j-a[i]+w[i])

dp[j]=max(dp[j],dp[j-a[i]+w[i])

好好对比下就明白了
所以我们对这个题进行降维书写
然后一定要注意到 当n>30时 我们一定要多加一句

	if (i >= 30)dp[i][30]
 = max(dp[i - 1][30] + 0, dp[i][30]);

为什么呢 因为你会发现 他这个30如果只是在for循环更新永远不能从dp[i-1][]30]就行更新 都是29
而在后面的那个代码

dp[i - 1][j] + (a[i] >> j) - k)

它是指此刻用的好钥匙 而我们其实是想用30多把坏的呢


	for(int i=1;i<=n;i++)
	{int maxn=0;int flag;
	  for(int j=30;j>=0;j--)
	  {
		  if(j>=1)dp[j]=max(dp[j]+(a[i]>>j)-k,dp[j-1]+(a[i]>>j));
		 else dp[j]=dp[0]+a[i]-k;
		  if(dp[j]>maxn){
			  maxn=dp[j];
			  flag=j;
		  }
	  }
	}

第三个题

这道题考的很好

首先需要仔细审题

如果两个圆舞可以通过选择第一个参与者转化为另一个圆舞,则两个圆舞没区别
我忽视了这句话
这句话是什么意思 就是 12 3 4 和2 1 3 4 是没区别的 我以为什么了你知道吗 我以为 12 3 4 的全排列都没区别。。。。
然后这其实是个圆排列 由于是圆 没有头区分 所以是n!/n=(n-1)!
然后这个题可以分成多少组就是
\(C_n^\frac{n}{2}\)*\(\frac{1}{2}\) 然后这个圆排列的方案是\((\frac{n}{2}-1)!^2\) 因为有两组嘛

圆排列:

有5对夫妻参加一场婚礼,他们被安排在一张10个座位的圆桌就餐,
但是操办者不知道他们之间的关系,随机安排座位,问5对夫妻恰好相邻而坐的概率是多少?

要研究圆桌排列,就必须知道它和直线排列组合的区别,
举个例子,5个人排成一排有多少种方式?同学们都知道A(5,5)=5!,但是当5个人坐成一圈时,
有多少种方式?很多同学会陷入死胡同,
其实两个题目关键区别在于直线排列时排列之前相对位置已经被确定,
但是圆桌问题时每个位置都不确定,但是这种题目我们只需要先找寻任意一人A坐下,
其余人相对位置也就确定了,
比如我们可以说一个在A左面,或者是A对 面等等,所以当5个人坐成一圈时, 有A(4,4)=4!
以上来源于百度文库

没有队头区分

第四个题

这个题我没想到是DP

你会发现很多题 我都想不到是dp
因为我不会dp
再者是这道题真的很难 四维背包dp
这个数据很小的 应该考虑dp的
好了 让我们来思考下做法吧

首先看到一般元素我们可以思考到其中一维应该表示选取元素 在看到是倍数 想到取模对吧!
于是这个四维就诞生了

这道题真的很有意思 你会发现这种不同层之间有关联的 如何进行转移呢
官方代码给了一个很有创意的办法
下面一起讲到

我们假设第三维是选取的个数c
第四维是余数r

然后考虑转移公式

我们思考下对于i,j他来源于前一个i,j-1对吧

那么它可以怎么转移呢
第一种可能 我们可以不选
\(a_{i,j}\)这个元素 那么
转移中可以这样写
dp[i][j][c][r]=dp[i][j-1][c][r]
但是一定要注意了 对于dp[i][j][c][r]而言 他不仅仅是只由dp[i][j-1][c][r]转移过来的 比如说此时的c是2表示选了两个元素
那我们由j-1的选了2个的元素转过来了 也可以是j-1-1-1的选了两个元素转移过来 当然了这里都是一样的

所以这里是要取max处理的

我当时这里琢磨了半天

我是对代码每一个细节都不许放过的!

然后我们再思考 如果要用这个元素的

我们该怎么推导这个状态转移方程呢

很明显一旦选取了元素 那么注定会导致余数的改变
int t=r+\(a_{i,j}\)%k
转移方程应该是这样的
我们该思考转移前这二者的关系
dp[i][j][c+1][t]

dp[i][j-1][c][r]+\(a_{i,j}\)
对吧
很明显 我如果选了这个元素他太是这个转移过来的
然后大家肯定会想到 我们是取max的
为什么呢 而不是直接等于他呢
因为dp[i][j-1][c+1][t]可能也很大 我们还是要做一个对比的 如果很大的话就取他了
然后我们可以得出(就在我写这话的时候我还是错误的理解,突然开窍了,也可以看出我做这个题也不是全懂的 这也是写题解的好处)

这个c是表示整行的选取!表示本行已经选取了c个元素了,不是这个人做第c个选取(这个人做第c个的结尾)的意思,我之前一直这么认为!

那么我们总结得出
dp[i][j][c+1][t]=max(dp[i][j-1][c][r]+\(a_{i,j}\),dp[i][j-1][c+1][t])

写错了 知道哪里吗

dp[i][j-1][c+1][t]

这里错了 为什么?

我们是说来到j的时候表示现在取了c个 但是你能不能保证之前的j-1没有取到c+1个吗 并且余数还不等于t?对吧

然后供上我的错解

我是这么随便的认为可能
整个for循环0-k-1
+\(a_{i,j}\)会导致余数重复为某个值了 实际上是不会的
\(a_{i,j}\)+x=t 那这个t是不会说
会重复的
简单证明下

(0+x)%k
(1+x)%k
....
会重复吗?不会 只是所有人都+了个x%k而已 你可以理解为整体右移动!

所以说我的理解是站不住脚的

所以这里是
dp[i][j][c+1][t]=max(dp[i][j-1][c][r]+\(a_{i,j}\),dp[i][j][c+1][t]

你以为就结束了吗?
不是的
终于写完了----单行的情况了

标签:这个,int,max,30,做不来,range,DP,小结,dp
From: https://www.cnblogs.com/LteShuai/p/18292455

相关文章

  • 使用资源编排 ROS 轻松部署单点网站——以 WordPress 为例
    介绍WordPress是一款免费开源的网站内容管理系统(CMS),它可以帮助用户简单快捷地创建和管理自己的网站,包括博客、新闻网站、电子商务网站、社交网络等等。WordPress有丰富的主题和插件库,使得用户可以轻松地为网站定制外观和功能。WordPress的易用性和可扩展性使其成为世界上最受欢......
  • 牛客周赛 Round50 E-小红的树上移动 (期望dp+逆元)
    E-小红的树上移动题目:题意:在一个树上从根节点移动,每次都会向更深的下一层走,如果此时已经是叶子节点没有下一层就会停留在这里。求出移动次数的期望,移动次数就是从根节点1开始到此节点的深度。思路:画一个草图不难看出其实在同一层中,到达每个点的概率是一样的。并且,对于每一层......
  • Profibus转ModbusTCP网关模块实现Profibus_DP向ModbusTCP转换
    Profibus转ModbusTCP网关模块实现Profibus_DP向ModbusTCP转换Profibus和ModbusTCP是工业控制自动化常用的二种通信协议。Profibus是一种串口通信协议,它提供了迅速靠谱的数据传输和各种拓扑结构,如总线和星型构造。Profibus可以和感应器、执行器、PLC等各类设备进行通信。ModbusTC......
  • Pyodps2节点连接linux服务器(paramiko 检查文件是否存在)
    在maxcomputer加入paramiko相关资源包1#!/usr/bin/python2#-*-coding:UTF-8-*-34##@resource_reference{"six.zip"}5##@resource_reference{"PyNaCl-1.4.0.zip"}6##@resource_reference{"paramiko-2.7.2.zip"}7##@resource_r......
  • Oracle数据库使用expdp/impdp导出导入数据
    背景:正式环境数据同步到测试环境,数据库名:MYDB,正式、用户:MYUSER(必须拥有SYS权限)。1、正式环境备份数据库(1)正式服务器上,cmd输入sqlplus,使用MYUSER账户登录(2)创建一个自定义的目录,用于存放导出的数据createdirectoryDATA_OUT_FILEas'E:\app\Administrator\admin\MYDB\my_dir\'......
  • P2964 [USACO09NOV] A Coin Game S (博弈论 dp)
    P2964[USACO09NOV]ACoinGameS博弈论dp(乱取的)两个人都希望自己的价值最大,可以认为他俩是等价的。考虑设计dp状态,设\(f_{i,j}\)表示考虑了前\(i-1\)个,现在的先手\([i,i+j-1]\)个,他之后能得到的最大价值。转移肯定是从\(f_{i+j,k}\)转移过来,并且\(1\lek\le2j\)......
  • 腾讯云篇7、手动搭建 WordPress 个人站点(Linux)
    操作场景WordPress是一款使用PHP语言开发的博客平台,您可使用通过WordPress搭建属于个人的博客平台。本文以CentOS7.6操作系统的腾讯云云服务器为例,手动搭建WordPress个人站点。示例软件版本本文搭建的WordPress个人站点组成版本及说明如下:Linux:Linux操作系统,......
  • 数位DP
    数位\(DP\)前言终于有时间来填这个大坑了啊。数位\(DP\)是一种比较冷门的动态规划问题。其一般都具有以下特征:出现连续的数字失去某一位,不能选哪个数整除某个数字在一个区间里面寻找合法解的数量打法递推法和递归法在数位\(DP\)中较为常见。递推法为先......
  • 生成扩散模型漫谈(四):DDIM = 高观点DDPM
    相信很多读者都听说过甚至读过克莱因的《高观点下的初等数学》这套书,顾名思义,这是在学到了更深入、更完备的数学知识后,从更高的视角重新审视过往学过的初等数学,以得到更全面的认知,甚至达到温故而知新的效果。类似的书籍还有很多,比如《重温微积分》、《复分析:可视化方法》等。回到......
  • 生成扩散模型漫谈(一):DDPM = 拆楼 + 建楼
    说到生成模型,VAE、GAN可谓是“如雷贯耳”,本站也有过多次分享。此外,还有一些比较小众的选择,如flow模型、VQ-VAE等,也颇有人气,尤其是VQ-VAE及其变体VQ-GAN,近期已经逐渐发展到“图像的Tokenizer”的地位,用来直接调用NLP的各种预训练方法。除了这些之外,还有一个本来更小众的选择——扩......