首页 > 其他分享 >21前两题

21前两题

时间:2024-10-11 16:21:43浏览次数:4  
标签:21 int times 枚举 两题 廊桥 dp mod

廊桥分配

考虑廊桥个数不会影响飞机停靠,所以我们可以将廊桥的个数限制拿掉来看待这个问题。只需要维护一个廊桥的优先队列,然后让飞机每次选取最小的廊桥停靠,如果廊桥有 \(i\) 个,那么到 \(i+1\) 个廊桥就相当于没有停靠到,但是每个廊桥停靠的飞机数目还是一定的。所以我们不妨直接设廊桥个数无限,到了第几个就是做到第几个的前缀和。然后进行模拟,维护一个等待飞走的飞机的优先队列,维护离去的时刻和占用的廊桥,每次弹出离开的,解放廊桥。所以时间复杂度 \(O(n+m+nlogn)\) 。

#include<bits/stdc++.h>
#define pir pair<int,int>
using namespace std;
const int N=1e5+5;
int n,m1,m2,s1[N],s2[N],maxi;
struct air{
	int c,l;//come and leave
}a[N],b[N];
void cal(air *q,int m,int *s){
	priority_queue<pir,vector<pir>,greater<pir> > q1;
	priority_queue<int,vector<int>,greater<int> > q2;
	for(int i=1;i<=n;++i) q2.push(i);
	for(int i=1;i<=m;++i){
		while(!q1.empty()&&q1.top().first<=q[i].c){
			//解放廊桥
			q2.push(q1.top().second); 
			q1.pop();
		}
		if(q2.empty()) continue;
		q1.push(make_pair(q[i].l,q2.top()));
		s[q2.top()]++;
		q2.pop();
	} 
	for(int i=1;i<=n;++i) s[i]+=s[i-1];
	return;
}
bool cmp(air x,air y){
	return x.c<y.c;
}
int main(){
	scanf("%d %d %d",&n,&m1,&m2);
	for(int i=1;i<=m1;++i) scanf("%d %d",&a[i].c,&a[i].l);sort(a+1,a+m1+1,cmp);
	for(int i=1;i<=m2;++i) scanf("%d %d",&b[i].c,&b[i].l);sort(b+1,b+m2+1,cmp);
	cal(a,m1,s1),cal(b,m2,s2);
	for(int i=0;i<=n;++i) maxi=max(maxi,s1[i]+s2[n-i]);
	printf("%d",maxi);
	return 0;
}

括号序列

不考虑枚举 * 而是用来构成合法状态是突破口,设计好的 dp 状态是关键。

为了不算重,我们设计6种状态

0.全为*型

  1. \((……)\) 括号包含型
  2. $ (……)(……)(……)** $
  3. \((……)**(……)**(……)\)
  4. \(**(……)**(……)**(……)\)
  5. \(**(……)**(……)**\)

考虑转移。

​ 0. \(dp_{l,r,0}=dp_{l,r-1,0} \ \&\& (s[r]=='?' \ | \ | \ s[r]=='*')\)。就是继承 \(r-1\)。

​ 1.\(dp_{l,r,1}=dp_{l+1,r-1,0}+dp_{l+1,r-1,2}+dp_{l+1,r-1,3}+dp_{l+1,r-1,4}\times ((s[l]=='?' \ | \ | \ s[l]=='(' \ )\&\& (s[r]=='?' \ | \ | \ s[r]==')' \ ) \ )\)。就是如果括号可以匹配,就把括号内的全部包进去统计答案。

​ 2.\(dp_{l,r,2}=\sum\limits_{p=l}^{r-1} dp_{l,p,3}\times dp_{p+1,r,0}\)。因为2显然可以由3和0拼接得来。

​ 3.\(dp_{l,r,3}=\sum\limits_{p=l}^{r-1} (dp_{l,p,3}+dp_{l,p,2})\times dp_{p+1,r,1}+ dp_{l,r,1}\)。首先要明确括号之间不一定非要有*,所以是2、3合起来向3转移。因为3包含1,所以要加上这个区间1可能的答案,注意是枚举完了才累加。

​ 4.\(dp_{l,r,4}=\sum\limits_{p=l}^{r-1} (dp_{l,p,4}+dp_{l,p,5})\times dp_{p+1,r,1}\)。同理,不过这个转移也可以是 \(dp_{l,p,0}\times dp_{p+1,r,3}\)。

​ 5.\(dp_{l,r,5}=\sum\limits_{p=l}^{r-1} dp_{l,p,4}\times dp_{p+1,r,0}+dp_{l,r,0}\)。5可由4、0拼接而来,然后0也属于5。

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,k;
char s[505];
long long dp[505][505][7];
int read(){
	char ch;int x=0,f=1;
	while(!isdigit(ch=getchar())){
		if(ch=='-') f=-1;
	}
	while(isdigit(ch)){
		x=(x<<1)+(x<<3)+(ch-'0');
		ch=getchar();
	}
	return x*f;
}
int main(){
	freopen("bracket.in","r",stdin);
	freopen("bracket.out","w",stdout);
	n=read(),k=read();
	scanf("%s",s+1);
	for(int i=1;i<=n;++i) dp[i][i-1][0]=1;
	for(int len=1;len<=n;++len){
		for(int l=1;l+len-1<=n;++l){
			int r=l+len-1;
			if(len<=k) dp[l][r][0]=dp[l][r-1][0]&&(s[r]=='*'||s[r]=='?');
			if((s[l]=='?'||s[l]=='(')&&(s[r]=='?'||s[r]==')')) dp[l][r][1]=(dp[l+1][r-1][0]+dp[l+1][r-1][2]+dp[l+1][r-1][3]+dp[l+1][r-1][4])%mod;
			if(len>=2){
				for(int p=l;p<r;++p){
					dp[l][r][2]=(dp[l][r][2]+dp[l][p][3]*dp[p+1][r][0]%mod)%mod;
					dp[l][r][3]=(dp[l][r][3]+(dp[l][p][3]+dp[l][p][2])*dp[p+1][r][1]%mod)%mod;
					dp[l][r][4]=(dp[l][r][4]+(dp[l][p][4]+dp[l][p][5])*dp[p+1][r][1]%mod)%mod;
					dp[l][r][5]=(dp[l][r][5]+dp[l][p][4]*dp[p+1][r][0]%mod)%mod;
				}
			}
			dp[l][r][5]=(dp[l][r][5]+dp[l][r][0])%mod;
			dp[l][r][3]=(dp[l][r][1]+dp[l][r][3])%mod;
		}
	}
//	for(int len=1;len<=n;++len){
//		for(int l=1;l+len-1<=n;++l){
//			int r=l+len-1;
//			printf("%d %d %lld/%lld/%lld/%lld/%lld/%lld  ",l,r,dp[l][r][0],dp[l][r][1],dp[l][r][2],dp[l][r][3],dp[l][r][4],dp[l][r][5]);
//		}
//		printf("\n");
//	}
	printf("%lld",dp[1][n][3]);
	return 0;
} 

报数

筛法,注意卡常和范围。

数列

这个题还是比较难的。难点在于想到 \(S\) 的位数和 \(\{a_i\}\)的关系其实是二进制填数,而对于 \(S\) 的每一位都可以通过有多少个 \({a_i}\) 来构成唯一确定的状态。

总而言之,设计状态难。

我的思路历程是想到了 \(S\) 和 \(\{a_i\}\) 之间一一对应的关系,但是没有想到枚举当前位可能有多少个 \(\{a_i\}\)。这启示我以后要抓住题目的性质,持续深入地想问题。dp状态的设计要清晰确定可转移,还要满足子结构。dp的状态就是一个明确的语句,表达的意思就是你对题目答案是如何组成的理解。

设 \(dp_{i,j,s,t}\) 表示当前考虑到 \(S\) 的第 \(i\) 位,\(a\) 中我们已经确定了几个元素(注意,这里确定了几个元素是相对于 \(S\) 枚举到了第几位而言的,每多枚举一位都有可能让其不一样,而我们枚举的只是确定了几个元素,因为序列是无序的,我们不能说到了第 \(j\) 个元素,这是一种相对关系),到这一位为止有多少个 1 (为什么会想到这个呢?首先是因为题目中有1的个数的限制,其次是我们要确定这一个才能确定每一位的值,才能让 \(S\) 维持一个二进制数的性质,不然就成了什么十进制之类的数了,那样显然不利于解决问题,所以这一维对于我们确定当前处于什么阶段和状态的转移是不可缺少的),这一位向下一位进多少个1(这个和上一维同理)。

我们解决了状态的设计,那么转移方程式就清晰可见了。由于我们不好确定\(i-1\)位的状态,所以我们直接向下一位转移:

\[{\large dp_{i+1,j+p,s+(t+p)\%1,\lfloor \frac{(t+p)}{2} \rfloor}=\sum\limits_{p=0}^{n-j} dp_{i,j,s,t}\times v_{a_i}^p\times \binom{n-j}{p}} \]

我当前位可能有多个1,所以我要枚举有多少个,所以我就多确定了这么多个。有多少一就是上一位有多少一加上上一位的进位加上这一位新加了多少 \(\%2\),向前进同理。

注意范围和预处理。

注意到了\(m\)位有可能还是多个1,所以不能直接在\(m\)位统计答案,要向后面进位一下才可以。

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int n,m,k;
long long dp[105][35][35][17],C[105][35],pv[105][35],v[105],ans;
int main(){
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	scanf("%d %d %d",&n,&m,&k);
	for(int i=0;i<=m;++i) scanf("%lld",&v[i]);
	for(int i=0;i<=m;++i){
		pv[i][0]=1;
		for(int j=1;j<=n;++j) pv[i][j]=pv[i][j-1]*v[i]%mod; 
	}
	for(int i=0;i<=n;i++) C[i][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
	dp[0][0][0][0]=1;
	for(int i=0;i<=m;++i){
		for(int j=0;j<=n;++j){
			for(int s=0;s<=k;++s){
				for(int t=0;t<=n>>1;++t){
					for(int p=0;p<=n-j;++p){
						dp[i+1][j+p][s+((t+p)&1)][(t+p)>>1]=(dp[i+1][j+p][s+((t+p)&1)][(t+p)>>1]+(dp[i][j][s][t]*pv[i][p]%mod)*C[n-j][p]%mod)%mod;
					}
				}
			}
		}
	}
	for(int s=0;s<=k;++s){
		for(int t=0;t<=n>>1;++t){
			if(s+__builtin_popcount(t)<=k) ans+=dp[m+1][n][s][t],ans%=mod;
		}
	}
	printf("%lld\n",ans);
	return 0;
}

标签:21,int,times,枚举,两题,廊桥,dp,mod
From: https://www.cnblogs.com/mountzhu/p/18458701

相关文章

  • The 2021 ICPC Asia Shenyang Regional Contest
    目录写在前面E签到F签到JBFSB带权并查集H图论I数学L树形DP,容斥M字符串,离线,单调性G贪心写在最后写在前面比赛地址:https://codeforces.com/gym/103427。以下按个人向难度排序。唉唉国庆vp三场唯一打的还像人的一场,最后手里还有两道题在写可惜都没出来呃呃。被树上背......
  • 23 真题前两题
    密码锁没什么好说的,要么暴力判断,要么手推。消消乐我们观察一下这个能消除的结构,因为是每次消除相邻两个,所以不难想到很像括号匹配,或者说可消除的是有对称性的,所以我们一定可以找到一个节点开始反转左右手性,所以我们就可以用栈来保持前半部分的手性,后半部分遇到转折点就是可以消......
  • Arduino UNO R3自学笔记24 之 Arduino如何使用MAX7219控制多个数码管?
    注意:学习和写作过程中,部分资料搜集于互联网,如有侵权请联系删除。前言:前面学习了单个数码管的控制,但是在大多场合一个数码管是满足不了使用场景的,因此对于数码管的学习,应该学会用尽可能少的端口去驱动更多的数码管,在此情况下,MAX7219比较适合我们使用。1.MAX7219引脚及功能介绍......
  • 20222321 2024-2025-1 《网络与系统攻防技术》实验一实验报告
    一.实验内容1实验目标本次实践的对象是一个名为pwn1的linux可执行文件。该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想......
  • 洛谷 P7517 [省选联考 2021 B 卷] 数对
    题目传送门解题思路其实你只要知道:这题你就秒了。我们发现 ,于是开一个桶来统计每个数出现的数量。我们只需要枚举每一个数的倍数,然后统计。最后,如果一个数出现了多次,再特判一下即可。代码#include<bits/stdc++.h>usingnamespacestd;intn;intcnt[500001];......
  • 《大侠立志传》游戏闪退未响应提示“找不到cv210.dll”文件该怎么处理?大侠立志传游戏
    《大侠立志传》以其丰富的剧情和独特的玩法吸引着众多玩家。然而,启动游戏时若出现闪退未响应且提示“找不到cv210.dll”文件,着实令人苦恼。遇到这种情况该如何处理呢?下面为大家提供解决办法。cv210.dll的功能介绍cv210.dll是VisualC++RedistributablePackage的一部分,特别......
  • 出现adui21.dll错误怎么解决?深度解析adui21.dll错误原因及高效解决方案
    针对adui21.dll错误的解决,我们首先需要深度解析其错误原因,然后提供高效解决方案。以下是对该问题的详细分析和解答:一、adui21.dll错误原因深度解析系统文件丢失或损坏:不当关机、病毒感染、软件安装或卸载不当等都可能导致系统文件丢失或损坏,包括adui21.dll文件。驱动程......
  • 《Programming from the Ground Up》阅读笔记:p217-p238
    《ProgrammingfromtheGroundUp》学习第11天,p217-p238总结,总计22页。一、技术总结1.Ccompilingp216,Ccompilingissplitintotwostages-thepreprocessorandthemaincompiler。注:感觉这个写法不好,因为preprocessor和compiler都是对象,这里应该指动作。应该是:Cco......
  • FL Studio21.2.3.4004中文完整版,直接安装激活!免费且永久使用所有插件均可使用
    ......
  • 【FMC214】基于VITA57.1标准的4路12G SDI视频传输FMC子卡模块
     板卡概述FMC214是基于VITA57.1标准的4路12GSDI视频传输FMC子卡模块,该板卡可以作为一个理想的IO单元耦合至FPGA前端,4路BNC接口形式的SDI信号通过电平转换(线缆均衡器)连接至FMC(HPC)接口的高速串行总线上,与FPGA内部的万兆位级收发器(MGT)互联,FPGA内部的SDI固件IP来完成SDI的编解码。......