首页 > 其他分享 >0227模拟赛(狗蛋)

0227模拟赛(狗蛋)

时间:2023-02-27 22:45:42浏览次数:63  
标签:ch read ll 狗蛋 0227 leq dp now 模拟

\(~~~~\) 这场其实质量挺高的(比起前面来说)

\(~~~~\) 但我挂了80+,占到得分的一半QAQ

多线并行/「CF1765D」Watch the Videos

题意

\(~~~~\) 每个东西占的空间为 \(a_i\) ,总容量为 \(m\),第 \(i\) 件物品需要用 \(a_i\) 的时间浏览,用 \(1\) 的时间删除,删除完全完成后才释放空间,任何时候都只能浏览一个东西,但同时可以删除东西。求最小用多少时间把所有东西都浏览且删除。
\(~~~~\) \(1\leq n\leq 10^6,1\leq a_i\leq m\leq 10^9\).

题解

\(~~~~\) 注意到可以节约时间仅在于删除东西和浏览东西的重叠,那我们考虑什么情况下可以重叠:在删除 \(a_i\) 时浏览一个空间在 \(m-a_i\) 以内的物品,显然这个值越大越好,所以我们在 set 内直接 upper_bound 即可。

\(~~~~\) 而显然对于每个物品只要能重叠就必定重叠,因为你不重叠省下来也最多只能再满足一个,显然不优。

代码
查看代码
#include <bits/stdc++.h>
#define ll long long
#define PII pair<int,int>
#define mp(a,b) make_pair(a,b)
using namespace std;
template<typename T>void read(T &x)
{
    T f=1;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
ll Ans;
int arr[200005];
multiset <int> S;
int main() {
//	freopen("multithreading.in","r",stdin);
//	freopen("multithreading.out","w",stdout); 
	int T,n,m;read(T);
	while(T--)
	{
		read(n);read(m); S.clear(); Ans=0;
		for(int i=1;i<=n;i++) read(arr[i]),Ans+=arr[i]+1,S.insert(arr[i]);
		while(!S.empty())
		{
			int u=*prev(S.end()); S.erase(prev(S.end()));
			while("I am an idiot.")
			{
				auto it=S.upper_bound(m-u);
				if(it==S.begin()) break;
				it--; u=*it,Ans--,S.erase(it);
			}
		}
		printf("%lld\n",Ans);
	}
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。

也就是找到最多后继使得可以同时进行
那么贪心地每个点去找最大的可以匹配的后继点即可。  
*/

空当接球

题意

\(~~~~\) 给出 \(n\) 堆球,每堆球初始都在 \([1,m]\) 之内。每次操作可以选择不同的 \(i,j\) 满足 \(a_i \geq a_j\),则令 \(a_i' \leftarrow a_i-a_j\),\(a_j'\leftarrow 2a_j\)。请构造 \(8\times 10^5\) 内操作,使得最后只有最多两堆球(两个数为 \(0\))。
\(~~~~\) \(1\leq n\leq 3\times 10^5,1\leq m\leq 10^{10}\).

题解

\(~~~~\) 很神仙的题。

\(~~~~\) 考虑对于较少堆的操作是左移 \(1\) 为,对于较多堆的操作,如果最开始最低位和较少堆是一样的,那我们把这两个操作过后最低位就是一样的。因此我们可以考虑按位开始考虑。

\(~~~~\) 那我们建出Trie树(从低到高建),注意到 \(a,b\) 从最低位开始相同的连续最多,那最低位的升高就越多,这样可以省下来更多的操作。所以我们从低位开始操作,不停往 \(0\) 儿子移动,同时操作 \(1\) 儿子,从底到顶合并,合并的LCA深度越深,那显然升位就越多。

\(~~~~\) 当然这样就只剩 \(\mathcal{O(\log n)}\) 的数了,剩下的随便乱搞合并应该也能过,当然还是介绍一下正解。

\(~~~~\) 对于 \(a<b<c\) 的三个数,我们想一个快速清空某一个的方法。令 \(t=\lfloor \frac{b}{a} \rfloor\) ,把 \(t\) 的二进制位从低到高枚举,当某位为 \(0\) 时操作 \((a,c)\) ,否则操作 \((b,c)\),显然过程中始终有 \(a\leq c\),操作完成后 \(b \leftarrow b \bmod a\),这样最小值是变小了的。而假设 \(b\) 最终均匀随机落在 \([0,a)\) 内,最终应该很快就能清零。

代码
查看代码
#include <bits/stdc++.h>
#define ll long long
#define PII pair<ll,ll>
#define mp(a,b) make_pair(a,b)
using namespace std;
template<typename T>void read(T &x)
{
    T f=1;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
struct node{
	ll Val,id;
	node(){}
	node(ll V,ll Id){Val=V,id=Id;}
}P[300005];
vector <PII> op;
void OP(ll p,ll q,bool Ins);
struct Trie{
	ll ch[30000005][2],tot;
	vector <ll> V[30000005];
	Trie(){tot=1;}
	void Insert(ll Val,ll id)
	{
		ll now=1;
		for(ll i=0;i<=50;i++)
		{
			ll Bit=(Val>>i)&1;
			if(!ch[now][Bit]) ch[now][Bit]=++tot;
			now=ch[now][Bit];
		}
		V[now].push_back(id);
	}
	ll Solve(ll now)
	{
		if(!now) return 0;
		if(V[now].empty())
		{
			ll u=Solve(ch[now][0]),v=Solve(ch[now][1]);//剩下一个 
			if(!u||!v) return u|v;
			OP(u,v,1);
			return 0; 
		}
		ll Fi=-1,Se=-1;
		for(ll qwq=0;qwq<(ll)V[now].size();qwq++)
		{
			if(!(~Fi)) Fi=V[now][qwq];
			else
			{
				Se=V[now][qwq];
				OP(Fi,Se,1);
				Fi=Se=-1;
			}
		}
		return Fi==-1?0:Fi;
	}
	void dfs()
	{
		ll now=1;
		while(now) Solve(ch[now][1]),now=ch[now][0]; 
	}
}Trie;
void OP(ll p,ll q,bool Ins=true)
{
	if(P[p].Val<P[q].Val) swap(p,q);
	P[p].Val-=P[q].Val; P[q].Val<<=1;
	op.push_back(mp(P[p].id,P[q].id));
	if(Ins&&P[p].Val) Trie.Insert(P[p].Val,P[p].id);
	if(Ins&&P[q].Val) Trie.Insert(P[q].Val,P[q].id); 
}
set<PII>S;
void Print()
{
	printf("%lld\n",(ll)op.size());
	for(ll i=0;i<(ll)op.size();i++) printf("%lld %lld\n",op[i].first,op[i].second);
	exit(0);
}
ll arr[500005];
int Del(int ind1,int ind2,int ind3)
{
	while("I am an idiot.")
	{
		if(!P[ind1].Val) return ind1;
		if(!P[ind2].Val) return ind2;
		if(!P[ind3].Val) return ind3;
		if(P[ind1].Val>P[ind2].Val) swap(ind1,ind2);
		if(P[ind2].Val>P[ind3].Val) swap(ind2,ind3);
		if(P[ind1].Val>P[ind2].Val) swap(ind1,ind2); 
		ll V=P[ind2].Val/P[ind1].Val;
		for(int B=0;V>>B;B++)
		{
			if((V>>B)&1) OP(ind1,ind2,0);
			else OP(ind1,ind3,0);
		}
	}
}
int main() {
//	freopen("ball.in","r",stdin);
//	freopen("ball.out","w",stdout);
	ll n,m;
	read(n);read(m);
	for(ll i=1,x;i<=n;i++)
	{
		read(x);P[i]=node(x,i);
		Trie.Insert(x,i);
	}
	Trie.dfs();int cnt=0;
	for(ll i=1;i<=n;i++) if(P[i].Val) P[++cnt]=P[i];
	vector <int> Tmp;
	for(int i=1;i<=cnt;i++)
	{
		Tmp.push_back(i);int res;
		if(Tmp.size()==3)
		{
			int T1=Tmp[0],T2=Tmp[1],T3=Tmp[2];
			res=Del(Tmp[0],Tmp[1],Tmp[2]);
			Tmp.clear();
			if(res==T1) Tmp.push_back(T2),Tmp.push_back(T3);
			if(res==T2) Tmp.push_back(T1),Tmp.push_back(T3);
			if(res==T3) Tmp.push_back(T1),Tmp.push_back(T2);
		}
	}
	Print();
	return 0;
}
/* 
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。
*/

列序号括/「CF1610G」AmShZ Wins a Bet

题意

\(~~~~\) 给出一个括号串,进行若干次(可以为 \(0\))次操作,每次操作允许删除 \(s_i,s_j\) 满足 \(i<j\) 且 \(s_i='(',s_j=')'\)。求最后字典序最小的括号串。
\(~~~~\) \(1\leq |s|\leq 10^6\).

题解

\(~~~~\) 考场写了【九转大肠已删除】 一样的代码,然后被强强组题人卡到40,众生平等,狗门!蛋门!

\(~~~~\) 考虑一个性质,如果删了一个 \((i,j)\) 以内的括号,那中间的必定要跟着一起删,证明:

\(~~~~\) 如果中间夹了一个 ( 那删除这个 ( 显然可以使得更多的 ( 往前靠。如果夹了一个 ) 那删除这个 ) 可以使得 ) 往后延。综上所述,每次删肯定删的都是连续段。

\(~~~~\) 那我们就可以写一个 \(\mathcal{O(n^2)}\) 的 dp 了:\(dp_{i}\) 表示从 \([i,n]\) 字典序最小的串,\(to_i\) 表示与 \(i\) 位置上的左括号匹配的右括号,那么:

\(~~~~\) 若 \(to_i\) 存在,则 \(dp_{i}=\min(dp_{to_i+1},s_i+dp_{i+1})\) ,否则 \(dp_{i}=s_i+dp_{i+1}\)。根据上面的结论显然正确。

\(~~~~\) 现在优化这个dp:我们需要做的是:可持久化数据结构,支持在某个版本前加入字符,或比较两个版本的字典序(也即比较LCP),主席树?\(\mathcal{O(n \log^2 n)}\) ,危。

\(~~~~\) 我们来考虑倍增,\(f_{i,j}\) 表示从 \(i\) 开始的 \(dp\) 往后 \(2^j\) 个位置到哪里,\(Hash_{i,j}\) 表示从 \(i\) 开始的 \(dp\) 往后 \(2^j\) 个位置的Hash。在每个位置 \(\mathcal{O(\log n)}\) 维护上述两个东西,然后对每个位置LCP搞搞就好了。

代码
查看代码
#include <bits/stdc++.h>
#define PII pair<int,int>
#define mp(a,b) make_pair(a,b)
using namespace std;
template<typename T>void read(T &x)
{
    T f=1;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
const int MOD=998244353,base=233;
char S[1000005],f[1000005][22];
int n,Sta[1000005],Top,To[1000005],p[1000005][22],Hash[1000005][22],Pow[1000005],nxt[1000005];
int main() {
	scanf("%s",S+1); n=strlen(S+1); Pow[0]=1;
	for(int i=1;i<=n;i++) Pow[i]=Pow[i-1]*base%MOD;
	for(int i=1;i<=n;i++)
	{
		if(S[i]=='(') Sta[++Top]=i;
		else if(Top) To[Sta[Top--]]=i+1;
	}
	p[n+1][0]=nxt[n+1]=n+1;
	for(int i=n;i>=1;i--)
	{
		p[i][0]=nxt[i+1]; Hash[i][0]=S[i],nxt[i]=i;
		for(int j=1;j<=20;j++)
		{
			p[i][j]=p[p[i][j-1]][j-1];
			Hash[i][j]=(Hash[i][j-1]+1ll*Hash[p[i][j-1]][j-1]*Pow[1<<(j-1)]%MOD)%MOD;
		}
		if(To[i])
		{
			int x=i,y=nxt[To[i]];
			for(int j=20;~j;j--)
				if(p[x][j]&&p[y][j]&&Hash[x][j]==Hash[y][j]) x=p[x][j],y=p[y][j];
			if(y==n+1||S[x]>S[y]) nxt[i]=nxt[To[i]];
		}
	}
	int x=nxt[1];
	while(x<=n) putchar(S[x]),x=p[x][0];
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。
)(()(())))
)((())))

)((()())))
)((()())))
*/

可爱路径 / 「集训队互测2023 Round 6」>.<

没补,对不起

标签:ch,read,ll,狗蛋,0227,leq,dp,now,模拟
From: https://www.cnblogs.com/Azazel/p/17162257.html

相关文章

  • 计蒜客信息学2023年2月普及组模拟赛
    T1:外卖你当然可以通过直接全排列枚举走的顺序通过本题,但那样太麻烦了其实本题可以分为以下三种情况:\(A\)点在最左侧,那么最短距离\(=\)最大值\(-\)最小值\(A\)点......
  • [20230227]探究v$session.SQL_EXEC_ID在共享池(补充).txt
    [20230227]探究v$session.SQL_EXEC_ID在共享池(补充).txt--//http://blog.tanelpoder.com/2011/10/24/what-the-heck-is-the-sql-execution-id-sql_exec_id/--//上个星期测......
  • 文本左右对齐(字符串、模拟)、螺旋矩阵 II(数组、矩阵)、二叉树中的最大路径和(树、深
    文本左右对齐(字符串、模拟)给定一个单词数组和一个长度maxWidth,重新排版单词,使其成为每行恰好有maxWidth个字符,且左右两端对齐的文本。你应该使用“贪心算法”来放置......
  • 20230227-华为防火墙双机热备配置
    一、双机热备主要涉及到三个协议:VRRP:两台防火墙共享一个虚拟IP(VRRP只支持两台防火墙,不支持多台),同一个VRRP组的两个接口通过协商确定主(master)和备(backup)状态,只有主状态的防......
  • 雷电模拟器adb remount失败时的解决方法
    现象当我adbremount时报错:之前我执行过adbroot命令于是接下来执行:adbdisable-verity,但是报错:分析需要打开雷电模拟器的磁盘共享为System.vmdk可写入:参考:......
  • 算法题-模拟商场优惠打折
    模拟商场优惠打折:有三种优惠可以用,满减券,打折券和无门槛券满减券:满100减10,满200减20,依次递推打折券:92折,每次打折完向下取整,一次购物只能用一次无门槛券:一张券减5元,多张......
  • java学习日记20230227-java学习方法/转义字符/注释
    Java学习方法学习java基本原理和基本语法快速入门(基本程序CRUD)研究技术的注意事项,使用细节,使用规范,如何优化JAVA转义字符\t:一个制表位,实现对......
  • 带宽的概念(模拟信号和数字信号)
    如果从电子电路角度出发,带宽(Bandwidth)本意指的是电子电路中存在一个固有通频带,这个概念或许比较抽象,我们有必要作进一步解释。大家都知道,各类复杂的电子电路无一例外都......
  • 2023 年 CCF 春季测试赛模拟赛 - 2 题解
    T1约数和标准解法\(n=a_1^{b_1}\timesa_2^{b_2}\dotsa_k^{b_k}\)那么根据算术基本定理的推广,约数个数和约数和都是可以快速计算得到约数和sum\(sum=(a_1^0......
  • 2023 年 CCF 春季测试赛模拟赛 - 2
    T1分治,\(a^b+\dots+1=(a^{\lfloor\frac{b}{2}\rfloor}+\dots+1)\times(a^{\lfloor\frac{b}{2}\rfloor+1}+1)\)。如果\(b\)是偶数,需要减掉\(a^{b+1}\)。......