Akane-Weekly #2NOIP 十连测 (2)

Akane-Weekly #2:NOIP 十连测 (2)

今日得分:40+35+0+80=155,完全寄了

C.

神仙题。

简要题意:

给你一个正整数 \(x\) 和一个质数 \(p\) ,让你找三个正整数 \(a,b,c\) ,满足 \(ab+bc+ca=xp^2\) ,或者报告无解。

Solution:

首先,我们可以将 \(ab+bc+ca\) 转化为 \((a+b)(a+c)-a^2\) 。

所以我们有 \((a+b)(a+c)=xp^2+a^2\) 。

很直接想到试一下 \(a=p\) ,发现可以凑出 \(a=p,b=x+1-p,c=p^2-p\) 。

发现只有当 \(x+1-p>0\) 是可以成立,固这一类子问题已经解决。

当 \(p>x+1\) 的时候,我们可以类似地解决,令 \(p=k+(x+1)b(0<k\le x)\) 。

我们让 \(a=k\) ,代入推一下式子,可以得到 \(b=x+1-k\) 和

\[c=k^2+bx[(x+1)b+2k]-k \]

发现 \(b,c\) 显然大于 \(0\) ,只需要满足 \(a>0\) 即可。

当 \(a=0\) 时,发现 \(b=1\) ,不然 \(p\) 就不是质数了。

所以我们最后需要考虑一下 \(x=k+1\) 的情况。

我们化简式子得到

\[p^3+p^2+a^2=(a+b)(a+c) \]

待定系数,令 \(p^3+p^2+a^2=(p^2+yp+z)(p+u)\) 。

考虑到 \(zu\) 是完全平方数, \(z+yu=0\) 可以得到 \(-y\) 是完全平方数,枚举一下发现当 \(y=-4,u=3,z=12\) 时可以,所以有 \(a=6,b=p-3,c=p^2-4p+6\) 。

当然 \(p<=3\) 时不适用,手玩一下 \(x=1,p=2\) 和 \(x=2,p=3\) 的情况,发现均无解。

Code:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
    int X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
signed main(){
//	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t,x,p,a,b,c,k,by;
	t=read();
	while(t--){
		x=read(),p=read();
		if(x+1==p){
			a=6,b=p-3,c=p*p-4*p+6;
		}else{
			a=k=p%(x+1);
			by=p/(x+1);
			b=x+1-a;
			c=k*k+by*x*((x+1)*by+2*k)-a;
		}
		if((x==2&&p==3)||(x==1&&p==2)) printf("-1\n");	
		else printf("%lld %lld %lld\n",a,b,c);
	}
}

B.

简要题意:

对于每一个个体,有一下五种操作:

1.向前走一步。

2.向后走一步,如果有标记且向后走之后位置小于标记,那么删除标记。

3.在当前位置打一个标记,一个个体只保留位置最小的标记。

4.走到标记处并清空标记,如果没有标记则不动。

5.询问这个个体的位置。

现在有 \(n\) 个个体,同时把操作 \(1-4\) 改成区间操作。

每个个体的初始位置均为 \(5e5\) ,且保证操作种类随机。

\(n,q\le5e5\) 。

Solution:

显然要用线段树维护,但问题在于怎么写。

考虑随机性,我们可以用二进制暴力维护每个个体每一位是否有标记的状态,如果要清空标记就清空数组重新开始,如果要后退就缩掉最后一位,搞一个 \(long long\) 数组维护,叫作 \(abj\) 。

维护每个个体的位置数字 \(a\) ,但它不用上推,只有当上面有要对 \(a\) 修改的时候进行下推即可。

维护一个 \(bool\) 数组 \(flg\) ,表示区间是否有个体打上了标记,方便在操作 \(4\) 线段树上下推的时候判断终止,这个要 \(pushup\) 维护。

还有两个数组 \(fgl,fgr\) ,前者记录 \(abj\) 的位数,即已经往前走未回溯的步数,方便回退的时候减掉,如果要减的比 \(fgl\) 多,就记在 \(fgr\) 里面,当做懒标记下推即可。

操作 \(4\) 的时候即使找到了包含区间也要继续推来清除 \(flg\) ,不过由于随机性,时间也可以保证,(能过就可以了

~)

Code:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int x=0,f=1;
    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();
    return x*f;
}
int n,q;
bool flg[2000010];//表示标记(原题中的)为不为空。 
int fgl[2000010],fgr[2000010],a[2000010];
long long abj[2000010];//每一个梦境增加标记状态,状压,由于随机性,可以得到大概率不会超过64个未清除的标记,所以可以这样操作。(关键) 
struct tree{
	int l,r;
}t[2000010];
void pu(int id){
	flg[id]=abj[id]|flg[id<<1]|flg[id<<1|1];
} 
void get_abj(int id,int k){
	abj[id]|=k,flg[id]=1;
}
void get_new(int id,int k){
	abj[id]<<=k,fgl[id]+=k;
}
void get_a(int id,int k){
	a[id]+=k;
}
void get_d(int id,int k){
	if(k<64) abj[id]>>=k;
	else abj[id]=0;
	if(k<fgl[id]) fgl[id]-=k;
	else fgr[id]+=k-fgl[id],fgl[id]=0;	
}
void pd(int id){
	if(a[id]) a[id<<1]+=a[id],a[id<<1|1]+=a[id],a[id]=0;
	if(fgr[id]) get_d(id<<1,fgr[id]),get_d(id<<1|1,fgr[id]),fgr[id]=0;
	if(fgl[id]) get_new(id<<1,fgl[id]),get_new(id<<1|1,fgl[id]),fgl[id]=0;
	if(abj[id]) get_abj(id<<1,abj[id]),get_abj(id<<1|1,abj[id]),abj[id]=0;
}
void build(int id,int l,int r){
	t[id].l=l,t[id].r=r;
	if(l==r){
		a[id]=500000;
		return;
	}
	int mid=(l+r)>>1;
	build(id<<1,l,mid),build(id<<1|1,mid+1,r);
}
int query(int id,int x){
	if(t[id].l==t[id].r){
		return a[id];
	}
	pd(id);
	int mid=(t[id].l+t[id].r)>>1;
	if(x<=mid) return query(id<<1,x);
	else return query(id<<1|1,x);
}
void update3(int id,int l,int r){
	if(l<=t[id].l&&t[id].r<=r){
		get_abj(id,1);
		return;
	}
	pd(id);
	int mid=(t[id].l+t[id].r)>>1;
	if(l<=mid) update3(id<<1,l,r);
	if(r>mid) update3(id<<1|1,l,r);
	pu(id);
}
void update1(int id,int l,int r){
	if(l<=t[id].l&&t[id].r<=r){
		get_a(id,1),get_new(id,1);
		return;
	}
	pd(id);
	int mid=(t[id].l+t[id].r)>>1;
	if(l<=mid) update1(id<<1,l,r);
	if(r>mid) update1(id<<1|1,l,r);
	pu(id);
}
void update2(int id,int l,int r){
	if(l<=t[id].l&&t[id].r<=r){
		get_a(id,-1),get_d(id,1);
		return;
	}
	pd(id);
	int mid=(t[id].l+t[id].r)>>1;
	if(l<=mid) update2(id<<1,l,r);
	if(r>mid) update2(id<<1|1,l,r);
	pu(id);
}
void update4(int id,int l,int r){
	if(l<=t[id].l&&t[id].r<=r){
		if(t[id].l==t[id].r||(flg[id<<1]==0&&flg[id<<1|1]==0)){
			a[id]-=(abj[id]==0?0:63-__builtin_clzll(abj[id])); 
		}else{
			pd(id),update4(id<<1,l,r),update4(id<<1|1,l,r);	
		}
		abj[id]=fgl[id]=fgr[id]=flg[id]=0;
		return;
	}
	pd(id);
	int mid=(t[id].l+t[id].r)>>1;
	if(l<=mid) update4(id<<1,l,r);
	if(r>mid) update4(id<<1|1,l,r);
	pu(id);
}
int main(){
	n=read(),q=read();
	build(1,1,n);
	while(q--){
		int op,l,r;
		op=read(),l=read(),r=read();
		if(op==1) update1(1,l,r);
		if(op==2) update2(1,l,r);
		if(op==3) update3(1,l,r);
		if(op==4) update4(1,l,r);
		if(op==5) printf("%d\n",query(1,l));
	}
	return 0;
}
posted @ 2023-09-06 20:00  ArizonaYYDS  阅读(31)  评论(0)    收藏  举报