2019 USP Try-outs

题目链接
A.Kolkhozy
大意:询问区间中%m=x的数的个数
思路:离线+分块
询问区间 [ l , r ] [l,r] 等价于 [ 1 , r ] [ 1 , l 1 ] [1,r]-[1,l-1] 那么可以将询问拆成两部分,按照坐标递增排序。
枚举每个询问,按照m与 n \sqrt n 的关系进行分类, m > n m>\sqrt n 的时候显然不会有超过 n \sqrt n 个数满足,那么直接枚举即可。
m n m\leq \sqrt n 的时候可以用 f [ m ] [ x ] f[m][x] 记录 %m=x的个数。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int n,k,a[N],q;
int f[201][201];
struct uzi{
	int i,l,x,m,s;
	bool operator < (const uzi & t)const{
		return l<t.l;
	}
}p[N];
int cn[N],ans[N];
int main() {
  ios::sync_with_stdio(false);
 	cin>>n>>q;
 	for(int i=1;i<=n;i++){
 		cin>>a[i];
 	}
 	int cnt=0;
 	for(int i=1;i<=q;i++){
 		int l,r,x,m;
 		cin>>l>>r>>x>>m;
 		p[++cnt]={i,l-1,x,m,-1};
 		p[++cnt]={i,r,x,m,1};
 	}
 	sort(p+1,p+1+cnt);
 	int l=1,r=0;
 	while(l<=cnt){
 		while(r<p[l].l){
 			r++;
			for(int j=1;j<=200;j++){
				f[j][a[r]%j]++;
			}
			cn[a[r]]++;
 		}
 		if(p[l].m>200){
 			for(int j=p[l].x;j<=50000;j+=p[l].m){
 				ans[p[l].i]+=p[l].s*cn[j];
 			}
 		}else{
 			ans[p[l].i]+=p[l].s*f[p[l].m][p[l].x];
 		}
 		l++;
 	}
 	for(int i=1;i<=q;i++)cout<<ans[i]<<'\n';
 	return 0;
}

C.Crystal Matryoshkas
大意:给你n个重量为ai id为i的套娃。
m个操作,添加或删除一个套娃,询问包含id为x的套娃时最多能套几层。
思路:显然套娃从内到外 重量必然不减且满足 i = 1 x a i < = a x + 1 \sum_{i=1}^xa_i<=a_{x+1} ,那么最多能套的层数必然很小,因为他的重量是一个类等比数列的递增。那么直接用set维护当前所有套娃的重量,用map记录每个id的重量。然后先找到套在这个娃娃里面的套娃最多有多少,再找套在这个娃娃外面的套娃有多少即可。
ps:建议使用快读 关同步的cin 还是有点慢

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int n,m,a[N];
struct uzi{
	int i,l,r,s;
}p[N];
multiset<int>s;
map<int,int>w;
int main() {
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++){
  	scanf("%d",a+i);
  	w[i]=a[i];
  	s.insert(a[i]);
  }
  for(int i=1;i<=m;i++){
  	char x;
  	scanf(" %c",&x);
  	if(x=='+'){
  		int l,r;
  		scanf("%d%d",&l,&r);
  		w[r]=l;
  		s.insert(l);
  	}else if(x=='-'){
  		int l;
  		scanf("%d",&l);
  		auto x=s.find(w[l]);
  		s.erase(x);
  	}else{
  		int l;
  		scanf("%d",&l);
  		int ans=1;
  		vector<int>v;
  		auto x=s.find(w[l]);
  		s.erase(x);
  		v.pb(w[l]);
  		LL sa=0,g=w[l];
  		while(1){
  			if(s.size()){
  				auto x=s.lower_bound(sa);
  				if(*x>=sa && *x+sa<=g){
  					ans++;
  					sa+=*x;
  					v.pb(*x);
  					s.erase(x);
  				}else break;
  			}else break;
  		}
  		sa+=g;
  		while(s.size()){
  			auto x=s.lower_bound(sa);
  			if(x==s.end())break;
  			sa+=*x;
  			ans++;
  			v.pb(*x);
  			s.erase(x);
  		}
  		printf("%d\n",ans);
  		for(auto k:v){
  			s.insert(k);
  		}
  	}
  }
 	return 0;
}

F.Forbechenko v Rodvsky

大意:让你找到一个最小的进制c,使得a/b在c进制下是有限小数。
思路:转化题意就是,找到最小的c,使 a c k m o d    x = 0 ac^k\mod x =0
那么就是质因数分解a,b,c。用Miller_Rabin + Pollard_rho判一判就行了。
ps:a=1的时候要注意一下b。
这里送上Miller_Rabin + Pollard_rho的板子:

const int S=20;
mt19937 rd(time(0));
ll mul2(ll a,ll b,ll p){
	ll res=0;
	while(b)
	{
		if(b&1) res=(res+a)%p;
		a=(a+a)%p;
		b>>=1;
	}
	return res;
}
ll pow2(ll a,ll b,ll p){
	ll res=1;
	while(b){
		if(b&1) res=mul2(res,a,p);
		a=mul2(a,a,p);
		b>>=1;
	}
	return res;
}
int check(ll a,ll n,ll x,ll t){
	ll now,nex,i;
	now=nex=pow2(a,x,n);
	for(i=1;i<=t;i++)
	{
		now=mul2(now,now,n);
		if(now==1&&nex!=1&&nex!=n-1) return 1;
		nex=now;
	}
	if(now!=1) return 1;
	return 0;
}
int Miller_Rabin(ll n){
	if(n<2) return 0;
	if(n==2) return 1;
	if((n&1)==0) return 0;
	ll x,t,i;
	x=n-1;
	t=0;
	while((x&1)==0) x>>=1,t++;
	for(i=0;i<S;i++)
	{
		if(check(rd()%(n-1)+1,n,x,t)) return 0;
	}
	return 1;
}
ll Pollard_rho(ll x,ll c){
	ll i,k,g,t,y;
	i=1;
	k=2;
	y=t=rd()%x;
	while(1)
	{
		i++;
		t=(mul2(t,t,x)+c)%x;
		g=__gcd(y-t+x,x);
		if(g!=1&&g!=x) return g;
		if(y==t) return x;
		if(i==k)
		{
			y=t;
			k+=k;
		}
	}
}
vector<ll> fac;
void findfac(ll n){
	if(Miller_Rabin(n)){
		fac.pb(n);
		return;
	}
	ll t=n;
	while(t>=n) t=Pollard_rho(t,rd()%(n-1)+1);
	findfac(t);
	findfac(n/t);
}
void work(ll x){
	fac.clear();
	findfac(x);
}

G.Hunting leshys
题意:有n个独立点和每个点的权值 。2种操作。
1.连接i,j ,i为j的祖先。
2.询问i和i的所有祖先的最小权值
保证每个点只有一个祖先。
思路:并查集维护每个点的最终祖先和自己到最终祖先的路径上的最小值。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int a[N],n,m,f[N];
int find(int x){
	if(x==f[x])return x;
	int y=find(f[x]);
	a[x]=min(a[x],a[f[x]]);
	return f[x]=y;
}
int main() {
	scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++)scanf("%d",a+i),f[i]=i;
  for(int i=1;i<=m;i++){
  	char x;
  	scanf(" %c",&x);
  	if(x=='+'){
  		int l,r;
  		scanf("%d%d",&l,&r);
  		f[r]=l;find(r);
  	}else{
  		int l;
  		scanf("%d",&l);
  		f[l]=find(l);
  		printf("%d\n",a[l]);
  	}
  }
 	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40655981/article/details/106234584