2023.11.2

o.O ?


B

\(\{a_n\}\) 中选出若干数使得两两的乘积不为完全立方数。

\(n\le 10^5\)\(1\le a_i\le 10^{10}\),TL=1s.


如果其有一个 \(>10^5\) 的质因子一定对答案有贡献。

考虑其余的数,先令它们除去所有非 \(1\) 的完全立方因子。

若有多个 \(1\),只有一个对答案有贡献。否则一个数对应着一个唯一的数,从两个里选择出现次数最大的那个。

ll Pollard_Rho(ll n){
	if(!(n&1))return 2;
	ll d,x,y,c;
	while(true){
		d=1;
		for(int i=1;i<=128;i<<=1){
			x=0,y=0,c=rd()%(n-1)+1;
			for(int j=1;j<=i;j++){
				x=f(f(x,c,n),c,n),y=f(y,c,n);
				d=mul(d,abs(x-y),n);
			}
			if(__gcd(d,n)!=1)return __gcd(d,n);
		}
	}
}

非常好 Pollard-Rho,这使我的旋转。

不过还是过了。

点击查看代码
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#define ll long long
#define N 100010
#define M 60
using namespace std;
ll read(){
	ll x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
ll mul(ll x,ll y,ll p){
	return ((__int128)x)*y%p;
}
ll qpow(ll k,ll b,ll p){
	ll ret=1;
	while(b){
		if(b&1)ret=mul(ret,k,p);
		k=mul(k,k,p),b>>=1;
	}
	return ret;
}
mt19937 rd(233);
bool check(ll a,ll n){
	ll u=n-1,t=0;
	while(!(u&1))t++,u>>=1;
	ll x=qpow(a,u,n),tp;
	if(x==1)return false;
	for(int i=1;i<=t;i++,x=tp){
		tp=mul(x,x,n);
		if(x!=1&&x!=n-1&&tp==1)return true;
	}
	return x!=1;
}
bool Miller_Rabin(ll n){
	if(n==2)return true;
	if(n<2||(!(n&1)))return false;
	for(int i=1;i<=10;i++)
		if(check(rd()%(n-1)+1,n))return false;
	return true;
}
ll f(ll x,ll c,ll n){
	return (mul(x,x,n)+c)%n;
}
ll Pollard_Rho(ll n){
	if(!(n&1))return 2;
	ll d,x,y,c;
	while(true){
		d=1;
		for(int i=1;i<=128;i<<=1){
			x=0,y=0,c=rd()%(n-1)+1;
			for(int j=1;j<=i;j++){
				x=f(f(x,c,n),c,n),y=f(y,c,n);
				d=mul(d,abs(x-y),n);
			}
			if(__gcd(d,n)!=1)return __gcd(d,n);
		}
	}
}
ll pr[M];int cnt;
ll maxp;
void find(ll n){
	if(n==1)return;
	if(Miller_Rabin(n)){
		pr[++cnt]=n;
		maxp=max(maxp,n);
		return;
	}
	ll p=n;
	while(p==n)p=Pollard_Rho(n);
	find(p),find(n/p);
}
int _n;
int ans=0;
map<ll,int>id;int sid;
vector< pair<int,bool> >prm[N];
int s[N];
int main(){
	freopen("lovely.in","r",stdin);
	freopen("lovely.out","w",stdout);
	_n=read();
	for(ll x;_n;_n--){
		maxp=cnt=0,find(x=read());
		if(maxp>100000){ans++;continue;}
		sort(pr+1,pr+1+cnt);
		for(int i=1;i<=cnt;i++){
			if(i<=cnt-2&&pr[i]==pr[i+1]&&pr[i]==pr[i+2])
				x/=pr[i]*pr[i]*pr[i],i+=2;
		}
		if(!id[x]){
			id[x]=++sid;
			for(int i=1;i<=cnt;i++){
				if(i<=cnt-2&&pr[i]==pr[i+1]&&pr[i]==pr[i+2]){
					i+=2;continue;
				}
				prm[sid].push_back(make_pair(pr[i],i<cnt&&pr[i]==pr[i+1]));
				if(i<cnt&&pr[i]==pr[i+1])i++;
			}
		}
		s[id[x]]++;
	}
	for(int i=1;i<=sid;i++){
		ll x=1,y=1;
		for(pair<int,bool> t:prm[i]){
			x*=t.first*(t.second?t.first:1);
			y*=t.first*(t.second?1:t.first);
		}
		if(x==1)ans++;
		else{
			if(s[id[x]]>s[id[y]])ans+=s[id[x]];
			else if(s[id[x]]==s[id[y]]&&x>y)ans+=s[id[x]];
		}
	}
	printf("%d\n",ans);
	
	return 0;
}

原题是 [AGC003D] Anticube.

实现不是很精细,mt19937 用 233 被卡了两个点。

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define ll long long
#define N 500010
#define M 100
using namespace std;
ll read(){
	ll x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
ll mul(ll x,ll y,ll p){
	return ((__int128)x)*y%p;
}
ll qpow(ll k,ll b,ll p){
	ll ret=1;
	while(b){
		if(b&1)ret=mul(ret,k,p);
		k=mul(k,k,p),b>>=1;
	}
	return ret;
}
mt19937 rd(114514);
bool check(ll a,ll n){
	ll u=n-1,t=0;
	while(!(u&1))t++,u>>=1;
	ll x=qpow(a,u,n),tp;
	if(x==1)return false;
	for(int i=1;i<=t;i++,x=tp){
		tp=mul(x,x,n);
		if(x!=1&&x!=n-1&&tp==1)return true;
	}
	return x!=1;
}
bool Miller_Rabin(ll n){
	if(n==2)return true;
	if(n<2||(!(n&1)))return false;
	for(int i=1;i<=10;i++)
		if(check(rd()%(n-1)+1,n))return false;
	return true;
}
ll f(ll x,ll c,ll n){
	return (mul(x,x,n)+c)%n;
}
ll Pollard_Rho(ll n){
	if(!(n&1))return 2;
	ll x=rd()%(n-1)+1,y=x,c=rd()%(n-1)+1,ret=1;
	for(ll i=1;;i<<=1,y=x,ret=1){
		for(ll j=1;j<=i;j++){
			x=f(x,c,n);
			ret=mul(ret,abs(x-y),n);
			if(!(j&127)){
				ll d=__gcd(ret,n);
				if(d>1)return d;
			}
		}
		ll d=__gcd(ret,n);
		if(d>1)return d;
	}
}
ll pr[M];int cnt;
ll maxp;
void find(ll n){
	if(n==1)return;
	if(Miller_Rabin(n)){
		pr[++cnt]=n;
		maxp=max(maxp,n);
		return;
	}
	ll p=n;
	while(p==n)p=Pollard_Rho(n);
	find(p),find(n/p);
}
int _n;
int ans=0;
map<ll,int>id;int sid;
vector< pair<int,bool> >prm[N];
int s[N];
signed main(){
	_n=read();
	for(ll x;_n;_n--){
		maxp=cnt=0,find(x=read());
		if(maxp>100000){ans++;continue;}
		sort(pr+1,pr+1+cnt);
		for(int i=1;i<=cnt;i++){
			if(i<=cnt-2&&pr[i]==pr[i+1]&&pr[i]==pr[i+2])
				x/=pr[i]*pr[i]*pr[i],i+=2;
		}
		if(!id[x]){
			id[x]=++sid;
			for(int i=1;i<=cnt;i++){
				if(i<=cnt-2&&pr[i]==pr[i+1]&&pr[i]==pr[i+2]){
					i+=2;continue;
				}
				prm[sid].push_back(make_pair(pr[i],i<cnt&&pr[i]==pr[i+1]));
				if(i<cnt&&pr[i]==pr[i+1])i++;
			}
		}
		s[id[x]]++;
	}
	for(int i=1;i<=sid;i++){
		ll x=1,y=1;
		for(pair<int,bool> t:prm[i]){
			x*=t.first*(t.second?t.first:1);
			y*=t.first*(t.second?1:t.first);
		}
		if(x==1)ans++;
		else{
			if(s[id[x]]>s[id[y]])ans+=s[id[x]];
			else if(s[id[x]]==s[id[y]]&&x>y)ans+=s[id[x]];
		}
	}
	printf("%lld\n",ans);
	
	return 0;
}


C

给定串 \(s\),每次问 \(t\)\(s\) 中的出现次数,强制在线。

\(|s|,q,|t|,\sum |t|\le 10^5\)\(|\Sigma|=10^6\),TL=4s.


\(\sum |t|\) 很小,考虑对所有询问串的长度的出现次数分治。小的暴力 kmp,大的哈希。

最劣也就是 \(O(n\sqrt{n}\log n)\) 小常数。

  • 只使用 kmp 能够在 4s 内通过所有数据。

随机种子 233 又掉了 10 分。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define N 100010
#define M 1000010
using namespace std;
int read(){
	int x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
mt19937 rd(114514);
ull base=13331,value[M],pw[N],f[N];
void init(){
	pw[0]=1;
	for(int i=1;i<=100000;i++)pw[i]=pw[i-1]*base;
	for(int i=1;i<=1000000;i++)value[i]=rd();
}
int opt,n,q,a[N];
int len[N];vector<int>ch[N];
int occur[N],m,c[N];
vector< pair<ull,int> >s[N];
int t[N<<1],kmp[N<<1];
int main(){
	freopen("poem.in","r",stdin);
	freopen("poem.out","w",stdout);
	opt=read();
	n=read(),q=read();
	init();
	for(int i=1;i<=n;i++){
		a[i]=read();
		f[i]=f[i-1]*base+value[a[i]];
	}
	for(int i=1;i<=q;i++){
		len[i]=read(),occur[len[i]]++;
		for(int j=1;j<=len[i];j++)ch[i].push_back(read());
	}
	for(int i=1;i<=n;i++){
		if(occur[i]<=20)continue;
		for(int j=i;j<=n;j++)
			s[i].push_back(make_pair(f[j]-f[j-i]*pw[i],0));
		sort(s[i].begin(),s[i].end());
		int cur=0;
		for(pair<ull,int> &j:s[i])j.second=++cur;
	}
	int lastans=0;
	for(int i=1;i<=q;i++){
		m=len[i];int cur=0;
		for(int j:ch[i])c[++cur]=j^(opt*lastans);
		if(m>n){
			printf("%d\n",lastans=0);
			continue;
		}
		if(occur[m]>20){
			ull hsh=0;
			for(int i=1;i<=m;i++)
				hsh=hsh*base+value[c[i]];
			auto L=lower_bound(s[m].begin(),s[m].end(),make_pair(hsh,0));
			auto R=upper_bound(s[m].begin(),s[m].end(),make_pair(hsh,0x3f3f3f3f));
			if(R==s[m].begin()){
				printf("%d\n",lastans=0);
				continue;
			}
			R--;
			int l=(L==s[m].end())?m+1:L->second;
			int r=R->second;
			printf("%d\n",lastans=r-l+1);
			continue;
		}
		for(int i=1;i<=m;i++)t[i]=c[i];
		t[m+1]=0;int ans=0;
		for(int i=1;i<=n;i++)t[m+1+i]=a[i];
		for(int i=2,j=0;i<=m+1+n;i++){
			while(j&&t[i]!=t[j+1])j=kmp[j];
			if(t[i]==t[j+1])j++;
			kmp[i]=j;
			if(i>m+1&&kmp[i]==m)ans++;
		}
		printf("%d\n",lastans=ans);
	}
	
	return 0;
}

D

给出长 \(n\) 的排列 \(S,G\) 和数 \(k\).

对于 \(i\in[n-k+1,n]\),可以将 \(G[i:n]\) 随机打乱,最大化如下区间 \([l,r]\) 的个数:

  • 存在 \(S[x:y]\) 重排后与 \(G[l:r]\) 相同。

\(k\le n\le 2\times 10^5\).


100 + 100 + 85(90) +10 = 295(300).

posted @ 2023-11-02 15:07  SError  阅读(8)  评论(0编辑  收藏  举报