首页 > 其他分享 >CQBZ Round 12

CQBZ Round 12

时间:2023-09-11 21:44:41浏览次数:29  
标签:CQBZ 12 lc int void mid 括号 rc Round

首先,在本次考试中,我深刻认识到了常数优化的重要性。

我决心改掉 #define int long long 的坏习惯。

我们不能保证评测机的速度,我们只能保证自己代码的优秀。`

同时我要下定决心更改自己的思维方式。

我发现自身在做题时应合理利用时间,创造价值,不能出现T6这种写2.5h没拿一分的情况了。

我的思维方式是存在问题的,每当想到了复杂度正确的做法就开写,没有考虑到实现的细节以及复杂度是否真正正确。

导致实现+调试时遇到巨大困难。

magic

注意到 \(1\le a,b\le 10^{10}\),而限制条件一要求 \(x=y^2\),完全平方数只有 \(10^5\) 个。完全可以暴力枚举每一个完全平方数,然后 \(O(\log_{10} b)\) 判断即可。

复杂度 \(O(\sqrt b\log_{10}b)\)。

linear

设 \(a_0=a_1-1\),即求:

\[\min\lbrace\sum_{i=1}^n|a_0+i-b_i|\rbrace \]

设 \(c_i=i-b_i\),则根据中位数的性质,\(a_0\) 取 \(c\) 的中位数即可。

bracket

坑题。数据很小,我们可以在 \(O(n^3)\) 去处理一个括号,这里采用一对一对拆括号的形式。

先用栈处理出每个括号的对应位置。

然后枚举每一对括号进行拆解。这里我们枚举括号的右端点,秉承先拆小括号的原则。

将没有被拆的括号看作一个整体,也即一个字符

那么一个括号不能被拆的充要条件是:

  1. 左括号前有 *,/
  2. 括号内含有加减运算,注意我们将一个未被拆的括号看作一个元素

变号,前方是减号就变正负号,是除号就变乘除号。

void solve(){
	cin>>a+1;
	int n=strlen(a+1);
	for(int i=1;i<=n;i++){
		pos[i]=vis[i]=0;
		if(a[i]=='(')s.push(i);
		if(a[i]==')')pos[i]=s.top(),pos[s.top()]=i,s.pop();
	}
	for(int i=1;i<=n;i++){
		if(a[i]==')'){
			int tag=0;
			for(int j=pos[i]+1;j<i;j++){
				if(a[j]=='('&&vis[j]==0)j=pos[j]+1;
				if(a[j]=='+'||a[j]=='-')tag=1;
			}
			if(a[i+1]=='*'||a[i+1]=='/'||a[pos[i]-1]=='*'||a[pos[i]-1]=='/'){
				if(tag)continue;
			}
			vis[i]=vis[pos[i]]=1;
			if(a[pos[i]-1]=='-'){
				for(int j=pos[i]+1;j<i;j++){
					if(a[j]=='('&&vis[j]==0)j=pos[j]+1;
					if(a[j]=='+')a[j]='-';
					else if(a[j]=='-')a[j]='+';
				}
			}
			if(a[pos[i]-1]=='/'){
				for(int j=pos[i]+1;j<i;j++){
					if(a[j]=='('&&vis[j]==0)j=pos[j]+1;
					if(a[j]=='*')a[j]='/';
					else if(a[j]=='/')a[j]='*';
				}
			}
		}
	}
	for(int i=1;i<=n;i++){
		if(!vis[i])cout<<a[i];
	}
	cout<<"\n";
} 

treasure

简单的问题,显然我们是贪心地将路径的前面改为 a。我们计算 \(s_{i,j}\) 表示 \((1,1)\rightarrow (i,j)\) 使得路径上全是 a 的操作次数。

有 \(s_{1,1}=[a_{1,1}\neq \text{a}],s_{i,j}=\min(s_{i-1,j}(i>1),s_{i,j-1}(j>1))+[a_{i,j}\neq \text{a}]\)

然后 \(\forall i,j,s_{i,j}\le k,a_{i,j}\leftarrow\text{a}\)

成功将问题化为 \(k=0\) 的情况。

现在考虑求解这个问题。朴素的想法的BFS,虽然数据没卡,但可以被卡——复杂度是错的。

有一个显然的性质是,对于所有字符串的第 \(k\) 个字符,其必然是由某个点 \((x,y),x+y=k+1\) 跑来的。

这启发我们依次拼出每个字符。可以动态维护最优集合,设 \(f_{i,j}\) 表示当前点 \((i,j)\) 是否在最优集合中。

设当前在拼第 \(k\) 位,我们对于所有 \((x,y)\),满足 \(f_{x-1,y}|f_{x,y-1}\) 为真的点取字典序最小的字符,将这些更新,加入新的决策集合。

这样我们就可以 \(O(n^2)\) 地得到最优解了。

//We can make the k become 0 easily.
//How to do it when the k is equal to 0?
/*
One naive views is to use DP.But comparing two string needs O(n). 
Can we speed it?
Maybe we can use the MIM.Let it meet in the middle.
Through it,we can make the n reduce to the middle of before.
But the cost?
However,any act only be the (i+j-1)th.
So,We can make the set S to achieve it.
*/ 
void init(){
	cin>>n;int k;cin>>k;
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>a[i][j];
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
		s[i][j]=0x3f3f3f3f;
		if(i==1&&j==1){
			s[i][j]=(a[1][1]!='a');
			if(s[i][j]<=k)a[i][j]='a'; continue; 
		} 
		if(i>1)s[i][j]=min(s[i][j],s[i-1][j]);
		if(j>1)s[i][j]=min(s[i][j],s[i][j-1]);
		s[i][j]+=(a[i][j]!='a');
		if(s[i][j]<=k)a[i][j]='a'; 
	} 
	f[1][1]=1;ans[2]=a[1][1];
	for(int k=3;k<=(n<<1);k++){
		char x='z';
		for(int i=1;i<k;++i){
			if(k-i>n)continue;
			if(i>n)continue;
			if(f[i-1][k-i]|f[i][k-i-1])x=min(x,a[i][k-i]);
		}
		for(int i=1;i<k;++i){
			if(k-i>n)continue;
			if(i>n)continue;
			if(a[i][k-i]==x)f[i][k-i]=(f[i-1][k-i]|f[i][k-i-1]);
		}
		ans[k]=x;
	}
	for(int i=2;i<=(n<<1);i++)cout<<ans[i];
	cout<<"\n";
}

summation

其实是一个蛮简单的数位DP,可惜我考场上选择了开“更好想”的T6。。。。

考场做T6的2h+应该是可以做出此题的。。。

最精妙的地方:对于每一位数字统计贡献

我们考虑统计数字 \(d\) 的贡献,这里仍然采用填数的过程。

首先考虑没有最高位限制的情况:

设 \(f_{i}\) 为填了前 \(i\) 位的总贡献,设 \(g_{i}\) 为第 \(i+1\) 位填 \(d\),\(d\) 这一位造成的贡献(本质上是 \(d\) 在每一位上出现次数再乘上 \(10^k\))。

那么显然,我们枚举当前位填 \(k\),那么对于数字 \(d\) 只有三种影响:

  • \(k<d\),此时它排序后在 \(d\) 前面,则对 \(d\) 的贡献无影响,固有 \(f_{i+1}\leftarrow f_i,g_{i+1}\leftarrow g_{i}\)
  • \(k=d\),此时再填一个 \(d\) 的贡献也同样毫无变化,\(g_{i+1}\leftarrow g_{i}\),但对于 \(f\) 而言,之前的所有 \(d\) 都向高位移动了一格,且加上了这个 \(d\),固有 \(f_{i+1}\leftarrow 10f_{i}+g_{i}\)
  • \(k>d\),此时排序后在 \(d\) 后面,会导致 \(d\) 全部向高位移动一格,固有 \(f_{i+1}\leftarrow 10f_{i},g_{i+1}\leftarrow 10g_{i}\)

再考虑一下最高位限制,我们只需要对 \(f,g\) 再开一维,同时转移时候注意转移到的版本即可。

初始化:有最高位版本限制的 \(g_0=d\),其他都是0。这是为了保证没有最高位限制的的正确计算。

void solve(int d){
	g[0][1]=d;
	for(int i=0;i<n;i++){
		f[i+1][0]=f[i+1][1]=g[i+1][0]=g[i+1][1]=0;
		int x=a[i+1]-'0';
		for(int j=0;j<2;j++){
			for(int k=0;k<10;k++){
				if(j&&k>x)break;
				int s=(j&(k==x));
				if(k<d)f[i+1][s]=(f[i+1][s]+f[i][j])%p,g[i+1][s]=(g[i+1][s]+g[i][j])%p; 
				if(k==d)f[i+1][s]=(f[i+1][s]+10ll*f[i][j]+g[i][j])%p,g[i+1][s]=(g[i+1][s]+g[i][j])%p;
				if(k>d)f[i+1][s]=(f[i+1][s]+10ll*f[i][j])%p,g[i+1][s]=(g[i+1][s]+10ll*g[i][j])%p;
			}
		}
	}
	ans=(ans+f[n][1]+f[n][0])%p;
}

mid

注意到 \(m\) 远小于 \(n\) ,这启发我们用较小的时间预处理,用较长的时间进行回答。

这是区间第 \(k\) 大问题的变种。

求解区间第 \(k\) 大有两个通用的思路,一个是进行二分,根据排名进行判断,一个是使用主席树上二分+差分。

显然这个区间端点可移动是很恶心的。

根据最初的分析,不难想到二分这个第 \(k\) 大,判断它是否可行。

在这里,我最初的思想是,由于 \([b,c]\) 是必选,先求出在 \([b,c]\) 中小于 \(mid\) 的数的个数。然后考虑在 \([a,b-1],[c+1,d]\) 中选数。

这时候,问题变为贪心地找到一个区间 \([l,b-1]\),使得 \(cnt_{x\ge mid}-cnt_{x<mid}\) 最大,再找到一个区间 \([c+1,r]\),使得 \(cnt_{x\ge mid}-cnt_{x<mid}\) 最大。

这三个值加起来,如果大于了 \(\lfloor\frac{c-b+1}{2}\rfloor\) 就有解。

在代码上我是考虑对于每一个值域开主席树维护,标记永久化,具体做法就不详细说了,因为我挂了。

这引申出了一个重要的 Trick。

对于维护区间 \([l,r]\) 内满足某类限制的数的个数 \(c\) 与区间长度进行操作的问题,也即维护与 \(r-l+1-c\) 有关的问题,可以将满足该类限制的数看做 1,不满足的看做0.

在这里,将 \(x\ge mid\) 看做 1,其余看做 -1,问题变成了选出两个区间 \([l,b-1],[c+1,r],(l\ge a,r\le d)\) ,使得他们的和最大。

对于固定左/右端点的最大区间和问题,就是维护最大子段和里的向左向右子段和。

可以在主席树里进行维护。那么只需要 \(rmax_{[a,b-1]}+sum_{[b,c]}+lmax_{[c+1,d]}\ge 0\) 就说明区间中小于它的数字较少,中位数大于等于 \(mid\)。

而对于这个怎么维护呢?开一颗主席树,最初所有点权值都是1,进行离散化,然后按照权值进行插入,在版本 \(i\) 中将值为 \(i-1\) 的数全部单点修改为 -1.

时间复杂度为 \(O(n\log n+q\log^2 n)\)。

细节很多,这里给出代码进行参考.

#include<bits/stdc++.h>
using namespace std;
#define N 500500
#define int long long
int id,rt[N<<1],lc[N<<5],rc[N<<5],lx[N<<5],s[N<<5],rx[N<<5],a[N],b[N],c[N],n,m,f;
void build(int &x,int l,int r){
	x=++id;lx[x]=rx[x]=r-l+1;
	s[x]=r-l+1;
	if(l==r)return ;int mid=l+r>>1;
	build(lc[x],l,mid);
	build(rc[x],mid+1,r);
}
void pushup(int x){
	lx[x]=max(lx[lc[x]],s[lc[x]]+lx[rc[x]]);
	rx[x]=max(rx[rc[x]],s[rc[x]]+rx[lc[x]]);
	s[x]=s[lc[x]]+s[rc[x]];
}
void updata(int &x,int p,int l,int r,int pos,int k){
	x=++id;lc[x]=lc[p],rc[x]=rc[p],s[x]=s[p],lx[x]=lx[p],rx[x]=rx[p];
	if(l==r){
		s[x]=lx[x]=rx[x]=k;
		return ;
	}
	int mid=l+r>>1;
	if(pos<=mid)updata(lc[x],lc[p],l,mid,pos,k);
	else updata(rc[x],rc[p],mid+1,r,pos,k);
	pushup(x); 
}
struct node{
	int lx,rx,s;
};
node merge(node a,node b){
	node c;c.s=a.s+b.s;
	c.lx=max(a.lx,a.s+b.lx);
	c.rx=max(b.rx,b.s+a.rx);return c;
}
node find(int x,int l,int r,int L,int R){
//	cout<<"find : "<<l<<" "<<r<<" "<<lx[x]<<" "<<s[x]<<" "<<rx[x]<<"\n"; 
	if(L<=l&&r<=R)return (node){lx[x],rx[x],s[x]};
	int mid=l+r>>1;
	if(L<=mid&&mid<R)return merge(find(lc[x],l,mid,L,R),find(rc[x],mid+1,r,L,R));
	if(L<=mid)return find(lc[x],l,mid,L,R);
	return find(rc[x],mid+1,r,L,R); 
}
vector<int>g[N];
void init(){
	cin>>f>>n;
	for(int i=1;i<=n;i++)cin>>a[i],b[i]=a[i];
	sort(b+1,b+n+1);m=unique(b+1,b+n+1)-b-1;
	for(int i=1;i<=n;i++)c[i]=lower_bound(b+1,b+m+1,a[i])-b;
//	for(int i=1;i<=n;i++)cout<<c[i]<<" ";cout<<"\n";
	for(int i=1;i<=n;i++)g[c[i]].push_back(i);
	build(rt[1],1,n);
	int pq=m;
	for(int i=2;i<=m;i++){
		++pq;rt[pq]=rt[i-1];
		for(auto x:g[i-1]){
			updata(rt[pq+1],rt[pq],1,n,x,-1);++pq;
		}
		rt[i]=rt[pq];
	}
}
int query(int a,int b,int c,int d){
//	cout<<a<<" "<<b<<" "<<c<<" "<<d<<"\n"; 
	++a,++b,++c,++d;
	int l=1,r=m;
	while(l<r){
		int mid=l+r+1>>1;
		node you=find(rt[mid],1,n,a,b-1),arenot=find(rt[mid],1,n,b,c),alone=find(rt[mid],1,n,c+1,d);
//		cout<<mid<<" "<<you.rx<<" "<<arenot.s<<" "<<alone.lx<<"\n";
		you.rx=max(0ll,you.rx);alone.lx=max(0ll,alone.lx);
		if(you.rx+arenot.s+alone.lx>=0){
			l=mid;
		}
		else r=mid-1;
	}
	return l;
}
int in[4];
signed main(){
//	freopen("data.in","r",stdin);
//	freopen("data.out","w",stdout);
	ios::sync_with_stdio(false);
	init();int lst=0;
	int q;cin>>q;
	while(q--){
		for(int i=0;i<4;i++)cin>>in[i],in[i]=(in[i]+lst*f)%n;
		sort(in,in+4);
		lst=b[query(in[0],in[1],in[2],in[3])];
		cout<<lst<<"\n";
	}
}

标签:CQBZ,12,lc,int,void,mid,括号,rc,Round
From: https://www.cnblogs.com/oierpyt/p/17694604.html

相关文章

  • Django_debug page_XSS漏洞(CVE-2017-12794)漏洞复现
    目录1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞分析3、漏洞验证说明内容漏洞编号CVE-2017-12794漏洞名称Django_debugpage_XSS漏洞漏洞评级影响范围1.11.5版本漏洞描述修复方案1.1、漏洞描述1.11.5版本,修复了......
  • Codeforces Round 896 (Div. 1)
    Preface不管怎么说,最后还是被我苟上橙名了(虽然刚好2100整,不多不少)感觉我在1900~2100之间卡了好久好久,反观我的队友都是打上紫名后随便两三场就打上橙了,狠狠地羞辱我这个铁混子由于暑假集训打的校内排名比较高,作为新队伍也拿到了今年的一场CCPC+一场ICPC的名额,虽然要自费出行但......
  • SICTF-2023 round2
    前言又是挺长一段时间没有打ctf了,各种原因,要过一段时间才会继续上强度学安全吧QAQ。这个SICTF是被朋友拉过来打的,看了一下,还是挺有意思的。下面记录下题目,以及复习到的一些知识点吧。笔者真的是脑子不好使了签到Shop很简单的签到题目,算是一个整型溢出的类型。Different_gadget......
  • Codeforces Round 101 (Div. 2) C - E
    C.Queue(思维、排序、构造、*1800)题意:$n$个人排队,为他们构造一组身高,使得$x$的前面有$a_i$个人比他高。如果无法构造满足所有条件的身高序列,输出-1。思路:首先考虑,对于$a_i$较大的人,肯定尽可能地将其往队伍后面放,然后从后往前构造,因为只有$......
  • 亚马逊美国站桌面暖风机UL1278测试报告
    亚马逊美国站暖风机UL1278测试报告随之天气越来越冷,尤其是亚马逊那边更是大雪纷飞,早上冒着寒风回到办公室,双手都冻得通红,拿出来仿佛还冒着寒气,打字都打得不利索。冬天这么冷真的很影响工作效率,事情做不完又只能加班解决,为了能按时完成工作准时下班,还是给自己一个温暖的办公环境吧。......
  • Acwing.第 120 场周赛
    Acwing.第120场周赛比赛链接A最大GCD给定一个正整数n(n≥2),请你确定两个正整数a,b,使得1≤a<b≤n,且gcd(a,b)尽可能大。输出gcd(a,b)的最大可能值。gcd(a,b)指a,b的最大公约数。提示:可以通过给定样例观察一下n和答案之间的关系。输入格式第一行包含整数T,表示共有T......
  • 2.12 PE结构:实现PE字节注入
    本章笔者将介绍一种通过Metasploit生成ShellCode并将其注入到特定PE文件内的Shell注入技术。该技术能够劫持原始PE文件的入口地址,在PE程序运行之前执行ShellCode反弹,执行后挂入后台并继续运行原始程序,实现了一种隐蔽的Shell访问。而我把这种技术叫做字节注入反弹。字节注入功能调......
  • 【题解】Educational Codeforces Round 142(CF1792)
    没有手速,再加上被E卡了,废掉了。A.GamingForces题目描述:Monocarp正在玩电脑游戏。他打算杀死\(n\)个怪兽,第\(i\)个的血量为\(h_i\)。Monocarp的角色有两个魔法咒语如下,都可以以任意顺序用任意次(可以不用),每次使用相当于一次操作。选择两个怪兽并各扣一滴血。选择......
  • Codeforces Global Round 21 B. NIT Destroys the Universe
    给一个长为\(n\)的数组,可以执行以下操作任意次:选择\(l,r(1\leql<r\leqn)\),让\(\foralli(l\leqi\leqr),a_i=mex(\{a_l,a_{l+1},\cdots,a_{r}\})\)。问最小操作数使得\(\foralli,a_i=0\)。观察:答案\(\leq2\),因为对\([1,n]\)操作不超过两次......
  • 【230910-2】双曲线:y^2/160^2-x^2/120^2=1图线及特征
    【图像】【代码】<!DOCTYPEhtml><htmllang="utf-8"><metahttp-equiv="Content-Type"content="text/html;charset=utf-8"/><head><title>双曲线:y^2/160^2-x^2/120^2=1</title><styletype=&qu......