21杭电多校第九场

A

先构造出(1-8,16)(9)个数,共需要(17)

之后按照每四位一个单位构造数(x),若(x)的末四位(le 8)可以直接加,否则需要在之前(+1)然后减去一个(<8)的数

这样每一个(4)位最多用两步即可解决,一共最多(17+16 imes2+1=50)

(注意一直进位使得整个数多一位的情况下,中间会有一些(0),这些(0)节约了步数,使得总步数仍满足要求

#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b))%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void solve(ull x)
{
	if(x<16)
	{
		if(x<=8)
		{
			puts("p1");x--;
			if(x) printf("add %d
",10-x);
		}
		else printf("dup
sub %d
",10-(16-x));
		return ;
	}
	ull now=x&15;
	if(now<=8)
	{
		solve(x>>4);puts("mul 1");
		if(now) printf("add %d
",10-now);
	}
	else
	{
		solve((x>>4)+1);puts("mul 1");
		printf("sub %d
",10-(16-now));
	}
}
int main()
{
	ull n;rep(T,1,read())
	{
		cin>>n;
		if(!n) {puts("p1
sub 0
end");continue;}
		puts("p1");rep(i,1,7) printf("dup
add %d
",i);
		puts("dup
mul 7");solve(n);puts("end");
	}
}

B

博弈签到题 咕

C

对于一个数(x)的最大排名来说,需要找到最大的(k)满足较大的(k)(a_i)与较大的(k)(b_i)反向相加均大于(a_x+b_n)

因此需要对每一个(a_i)求出最小的(b_j)使(a_i+b_j>a_x+b_n),将(a)排序后由单调性可以通过简单求出

求出的所有(b)相当于一些限制,找到均满足这些限制的最大(k)即可

最小排名同理

#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b))%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define w first
#define id second
#define pb push_back
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,mn[MAXN],mx[MAXN],b[MAXN];
pii g[MAXN];
int main()
{
	int pos,res,cnt;rep(T,1,read())
	{
		n=read();rep(i,1,n) g[i]={read(),i};
		rep(i,1,n) b[i]=read();
		sort(g+1,g+n+1);
		rep(i,1,n) 
		{
			pos=n-1,res=n-1,cnt=0;dwn(j,n,1) if(i!=j)
			{
				cnt++;
				while(g[j].w+b[pos]<=g[i].w+b[n]&&pos) pos--;
				res=min(res,cnt+pos-1);
			}
			mx[g[i].id]=res+1;
		}
		rep(i,1,n>>1) swap(b[i],b[n+1-i]);
		rep(i,1,n)
		{
			pos=n-1,res=n-1,cnt=0;rep(j,1,n) if(i!=j)
			{
				cnt++;
				while(g[j].w+b[pos]>g[i].w+b[n]&&pos) pos--;
				res=min(res,cnt+pos-1);
			}
			mn[g[i].id]=n-res;
		}
		rep(i,1,n) printf("%d %d
",mn[i],mx[i]);
	}
}

D

看上去是个推式子概率题 咕

E

可做dp 咕

F

显然可以找到一个分界点,使得该点左侧的贡献为大于(x)的数的个数,右侧为小于

用树状数组直接维护所有数的出现,即可(O(log^2))找到分界点

统计答案可以用线段树分别维护小于/大于每个数的区间和,每次更改为区间加

#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 200100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b))%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int lim=2e5;
int n,q,w[MAXN];
ll pre[MAXN],suf[MAXN];
int sum[MAXN<<2];
ll sl[MAXN<<2],tl[MAXN<<2],sr[MAXN<<2],tr[MAXN<<2];
ll c[MAXN];
inline void addp(int x,int w){for(;x<=lim;x+=x&-x) c[x]+=w;}
inline ll query(int x,ll res=0){for(;x;x-=x&-x) res+=c[x];return res;}
inline ll getpre(int x){return query(x);}
inline ll getsuf(int x){return query(lim)-query(x-1);}
int find()
{
	int l=1,r=lim,mid=l+r>>1,res=-1;
	for(;l<=r;mid=l+r>>1)
		if(getpre(mid-1)<=getsuf(mid+1)) res=mid,l=mid+1;
		else r=mid-1;
	return res;
}
inline void upd(int k)
{
	sl[k]=sl[k<<1]+sl[k<<1|1],sr[k]=sr[k<<1]+sr[k<<1|1];
	sum[k]=sum[k<<1]+sum[k<<1|1];
}
inline void Mdfl(int k,int l,int r,int w)
{
	sl[k]+=1LL*sum[k]*w,tl[k]+=w;
}
inline void Mdfr(int k,int l,int r,int w)
{
	sr[k]+=1LL*sum[k]*w,tr[k]+=w;
}
inline void pshd(int k,int l,int r,int mid)
{
	if(tl[k]) Mdfl(k<<1,l,mid,tl[k]),Mdfl(k<<1|1,mid+1,r,tl[k]),tl[k]=0;
	if(tr[k]) Mdfr(k<<1,l,mid,tr[k]),Mdfr(k<<1|1,mid+1,r,tr[k]),tr[k]=0;
}
void build(int k,int l,int r)
{
	tl[k]=tr[k]=0;
	if(l==r)
	{
		sum[k]=w[l],sl[k]=pre[l-1]*w[l],sr[k]=suf[r+1]*w[l];
		return ;
	}
	int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
	upd(k);
}
void add(int k,int l,int r,int x,int w)
{
	if(l==r)
	{
		sum[k]+=w,sl[k]+=getpre(l-1)*w,sr[k]+=getsuf(r+1)*w;
		return ;
	}
	int mid=l+r>>1;pshd(k,l,r,mid);
	if(x<=mid) add(k<<1,l,mid,x,w);
	else add(k<<1|1,mid+1,r,x,w);
	upd(k);
}
void mdfl(int k,int l,int r,int a,int b,int w)
{
	if(a<=l&&r<=b) {Mdfl(k,l,r,w);return ;}
	int mid=l+r>>1;pshd(k,l,r,mid);
	if(a<=mid) mdfl(k<<1,l,mid,a,b,w);
	if(b>mid) mdfl(k<<1|1,mid+1,r,a,b,w);
	upd(k);
}
void mdfr(int k,int l,int r,int a,int b,int w)
{
	if(a<=l&&r<=b) {Mdfr(k,l,r,w);return ;}
	int mid=l+r>>1;pshd(k,l,r,mid);
	if(a<=mid) mdfr(k<<1,l,mid,a,b,w);
	if(b>mid) mdfr(k<<1|1,mid+1,r,a,b,w);
	upd(k);
}
ll qryr(int k,int l,int r,int x)
{
	if(l==r) return sr[k];
	int mid=l+r>>1;pshd(k,l,r,mid);
	return x<=mid?qryr(k<<1,l,mid,x):sr[k<<1]+qryr(k<<1|1,mid+1,r,x);
}
ll qryl(int k,int l,int r,int x)
{
	if(l==r) return sl[k];
	int mid=l+r>>1;pshd(k,l,r,mid);
	return x<=mid?sl[k<<1|1]+qryl(k<<1,l,mid,x):qryl(k<<1|1,mid+1,r,x);
}
ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
int main()
{
	int las,a,b,now;ll res,tot,g;
	rep(T,1,read())
	{
		n=read(),q=read();
		rep(i,1,n) w[read()]++;
		rep(i,1,lim) pre[i]=pre[i-1]+w[i];
		dwn(i,lim,1) suf[i]=suf[i+1]+w[i];
		rep(i,1,lim) if(w[i]) addp(i,w[i]);
		build(1,1,lim);
		while(q--)
		{
			a=read();
			if(a==2)
			{
				now=find(),res=qryr(1,1,lim,now);
				if(now<lim) res+=qryl(1,1,lim,now+1);
				tot=1LL*sum[1]*(sum[1]-1);
				g=gcd(res,tot);
				printf("%lld/%lld
",res/g,tot/g);
			}
			else
			{
				a=read(),b=read();addp(b,a);
				add(1,1,lim,b,a);
                if(b-1>=1) mdfr(1,1,lim,1,b-1,a);
                if(b+1<=lim) mdfl(1,1,lim,b+1,lim,a);
			}
		}
		rep(i,1,lim) w[i]=pre[i]=suf[i]=c[i]=0;
	}
}

G

直接维护这个链表,记录一下中点以及中点右侧点的集合。

删除与添加操作分别根据奇偶性讨论即可

#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 10010010
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b))%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int q,pre[MAXN],suf[MAXN],tot,n,ans,now,in[MAXN];
char s[5];
int main()
{
	int x,l,r;while(scanf("%d",&q)!=EOF)
	{
		rep(i,1,q)
		{
			scanf("%s",s+1);
			if(s[1]=='L')
			{
				tot++,now++;
				if(tot==1) pre[now]=suf[now]=0,suf[0]=pre[0]=now,ans=now,in[ans]=1;
				else
				{
					suf[now]=suf[0],pre[suf[0]]=now,pre[now]=0,suf[0]=now;
					if(tot&1) ans=pre[ans],in[ans]++;
				}
			}
			else if(s[1]=='R')
			{
				tot++,now++,in[now]++;
				if(tot==1) pre[now]=suf[now]=0,suf[0]=pre[0]=now,ans=now;
				else
				{
					pre[now]=pre[0],suf[pre[0]]=now,suf[now]=0,pre[0]=now;
					if(tot%2==0) in[ans]--,ans=suf[ans];
				}
			}
			else if(s[1]=='Q') printf("%d
",ans);
			else 
			{
				x=read();l=pre[x],r=suf[x];
				suf[l]=r,pre[r]=l;
				tot--;
				if(x==ans) {if(tot&1) ans=l,in[l]++;else ans=r;}
				else if(in[x]) {if(tot&1) ans=pre[ans],in[ans]++;}
				else {if(tot%2==0) in[ans]--,ans=suf[ans];}
				in[x]=0;
			}
		}
		while(ans) in[ans]=0,ans=suf[ans];tot=now=0;
	}
}

H

考虑取(m=2),则显然有最终答案(ge frac{n}{2}),考虑随机化令一个数在答案集合内

对于已知一个数的情况,朴素的想法是将其他数与这个数作差,想要找到一个质数(m)使得尽可能多的差是(m)的倍数

因为集合内的数较多,可以考虑再进行一次随机化,假定这个差也在集合中

则只需要先预处理出(sqrt{w})内的所有素数,对这个差进行质因数分解,然后(check)所有质因数的贡献

每次错误的概率为((1-frac{1}{4})),随机化(30)次错误的概率很低

#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 200100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b))%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,ntp[MAXN*10],p[MAXN*10],tot,ans,m;
ll g[MAXN],h[MAXN],f[MAXN];
void mem(int n=2e6)
{
	rep(i,2,n)
	{
		if(!ntp[i]) p[++tot]=i;
		rep(j,1,tot) if(i*p[j]>n) break;
			else {ntp[i*p[j]]=1;if(i%p[j]==0) break;}
	}
}
int solve(int pos,ll diff,int res=0)
{
	m=0;rep(i,1,tot)
		if(1LL*p[i]*p[i]>diff) break;
		else if(diff%p[i]==0)
			{h[++m]=p[i];while(diff%p[i]==0) diff/=p[i];}
	if(diff>1) h[++m]=diff;int tmp;
	rep(i,1,n) f[i]=abs(g[i]-g[pos]);
	rep(i,1,m)
	{
		tmp=0;
		rep(j,1,n) tmp+=(f[j]%h[i]==0);
		res=max(res,tmp);
	}
	return res;
}
int main()
{
	mem();int x,y;srand(19260817);
	rep(T,1,read())
	{
		n=read(),ans=1;rep(i,1,n) g[i]=read();
		rep(t,1,30) 
		{
			x=rand()%n+1,y=rand()%n+1;
			while(x==y) y=rand()%n+1;
			ans=max(solve(x,abs(g[x]-g[y])),ans);
		}
		printf("%d
",ans);
	}
}

I

奇怪的题 弃了

J

首先可以对(a,b)分别得到一个有效分数的区间,在区间外的贡献为最小值或最大值

有两种显然的情况,即完全不可能或一定可以达到目的

否则显然可以在有效区间内进行合法的选数使得(a)的分数恰好大于(b),此时的贡献为已有的二者分数之差

考虑能使答案更优的特殊情况,一定是在分数不变的情况下(a_n)更小或(b_n)更大

这两种情况分别发生在区间的左侧与右侧,判断一下二者的左侧区间与右侧区间本身是否合法

#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b))%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
ll n,a[MAXN],b[MAXN],s,t,h,ans,la,ra,lb,rb,res;
ll sa,sb;
int main()
{
	rep(T,1,read()) 
	{
		n=read(),s=read(),t=read(),h=read();
		rep(i,1,n-1) a[i]=read();rep(i,1,n-1) b[i]=read();
		sort(a+1,a+n);sort(b+1,b+n);
		ans=inf,sa=sb=0;ll tmp;
		rep(i,t+1,n-1-s) sa+=a[i],sb+=b[i];
		if(t) la=a[t],lb=b[t];else la=lb=1;
		if(s) ra=a[n-s],rb=b[n-s];else ra=rb=h;
		if(sa+ra<=sb+lb) {puts("IMPOSSIBLE");continue;}
		if(sa+la>sb+rb) {printf("%lld
",1-h);continue;}
		res=ans=sb-sa+1;
		if(sa+la>sb+lb) ans=min(ans,res-la+1);
		if(sa+ra>sb+rb) ans=min(ans,res-h+rb);
		printf("%lld
",ans);
	}
}

K

看上去可做的虚树+树剖题 咕

原文地址:https://www.cnblogs.com/yyc-jack-0920/p/15154851.html