题目链接
A.Kolkhozy
大意:询问区间中%m=x的数的个数
思路:离线+分块
询问区间
等价于
那么可以将询问拆成两部分,按照坐标递增排序。
枚举每个询问,按照m与
的关系进行分类,
的时候显然不会有超过
个数满足,那么直接枚举即可。
的时候可以用
记录 %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的套娃时最多能套几层。
思路:显然套娃从内到外 重量必然不减且满足
,那么最多能套的层数必然很小,因为他的重量是一个类等比数列的递增。那么直接用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,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;
}