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).