2021年USSTSIW寒假算法集训9 题解

92 阅读2分钟

G

题目链接

思路

ab=ka%b=k\frac{a}{b}=k\\ a\%b=k

因此有a=(b+1)ka=(b+1)k。因为b>kb>k,结合式子可以发现a>k2a>k^2,即k<ak<\sqrt a。所以考虑枚举余数kk。当kk确定时,aabb是一一对应的(原式形如一次函数)。因此只要确定有多少个bb满足条件,就可以知道当前的kk对答案的贡献是多少。
首先根据已知,k<byk<b\leq y。又因为axa\leq x,且a=(b+1)ka=(b+1)k,得到bxkkb\leq \frac{x-k}{k}。综上:b(k,min(xkk,y)]b\in(k,min(\frac{x-k}{k},y)]。其中每个bb都可以贡献一次答案。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(ll (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
void solve()
{
	ll x,y;
	In(2,&x,&y);
	ll lim=sqrt(x);
	ll ans=0;
	rep(k,1,lim)
	{
		ans+=max(0ll,min(y,(x-k)/k)-k);
	}
	Out(1,ans);
}
int main()
{
	int _;
	cin>>_;
	while(_--)
	{
		solve();
	}
}

J

题目链接

思路

异或运算满足结合律,因此可以维护一个异或和来找MEX。考虑如何快速地找MEX,这里用到了01trie01trie,将所有的数字加入01trie01trie中,并维护每个结点的子树大小。对于一次查询,从根节点向下贪心,途中维护答案。如果异或和的下一位为11,选11的叶结点更优,如果11的子树已经满了,就只能选00。如果异或和的下一位为00,就反过来做。另外要注意如果有一个要选的子树为空,直接输出当前结果即可。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
const int N=6E6+10;
ll n,m,tot=1;
ll a[N],t[N][2],siz[N];
void insert(ll val)
{
	ll cur=1;
	for(int i=19;i>=0;--i)
	{
		++siz[cur];
		if(val&(1<<i))
		{
			if(!t[cur][1])
				t[cur][1]=++tot;
			cur=t[cur][1];
		}
		else
		{
			if(!t[cur][0])
				t[cur][0]=++tot;
			cur=t[cur][0];
		}
	}
	++siz[cur];
}
ll query(ll val)
{
	ll cur=1,ret=0;
	for(int i=19;i>=0;--i)
	{
		if(val&(1<<i))
		{
			if(!t[cur][1])
				return ret;
			if(siz[t[cur][1]]==1<<i)
			{
				cur=t[cur][0];
				ret+=1<<i;
			}
			else
				cur=t[cur][1];
		}
		else
		{
			if(!t[cur][0])
				return ret;
			if(siz[t[cur][0]]==1<<i)
			{
				cur=t[cur][1];
				ret+=1<<i;
			}
			else
				cur=t[cur][0];
		}
	}
	return ret;
}
int main()
{
	In(2,&n,&m);
	rep(i,1,n)
		In(1,&a[i]);
	sort(a+1,a+n+1);
	n=unique(a+1,a+n+1)-a-1;
	rep(i,1,n)
		insert(a[i]);
	ll sum=0,x;
	while(m--)
	{
		In(1,&x);
		sum^=x;
		Out(1,query(sum));
	}
}