省选模拟26


A. 小 G 的约数

将给定的 \(n\) 分解质因数

按照每个因数含有的质因子次数和分类

答案就是最大的哪个

Code
#include
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,ans;
int c[100010],cnt;
int f[100010],siz;
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("divisor.in","r",stdin);
	freopen("divisor.out","w",stdout);
	n=read();
	for(int i=2;i*i<=n;i++) if(n%i==0){cnt++;while(n%i==0) c[cnt]++,n/=i;}if(n!=1) c[++cnt]=1;
	sort(c+1,c+1+cnt);f[0]=1;
	for(int i=1;i<=cnt;i++){
		for(int j=siz;~j;j--) for(int k=c[i];k;k--) f[j+k]+=f[j];
		siz+=c[i];
	}
	for(int i=1;i<=siz;i++) ans=max(ans,f[i]);
	printf("%lld\n",ans);
	return 0;
}

B. 小 G 的连通图

范围小的可以暴力

范围大的时候考虑构造一种方案

\(L=\prod_{i=1,i\ isprime}^{n}i\)

那么他与除了 \(L+1\) 的所有数都相连

调整这种方法使得 \(L+1\) 也被连入集合

找一个 \(a\) 使得 \(L+1\)\(L+a+1\) 相连

但这个时候 \(L\) 就不与 \(L+a\) 相连了

于是考虑再找一个 \(2a+1\)

这样 \(l+a\) 就与 \(l+3a+1\) 相连,同时 \(l+1+a\) 也相连了

同时 \(L\) 还和 \(L+3a+1\) 连在一起,所以就都连在一起了

为了方便构造于是要求 \(a\)\(2a+1\) 都是质数

最后得出 \(L\%a=a-1\)\(L\%(2a+1)=a+1\)\(L\) 为其他质数的倍数

\(CRT\) 合并一下就行,暴力枚举倍数也可以

Code
#include
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define B 100000000
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,A,mod,res,t,mu;
int a[100010],len;
int prime[100010],cnt;
int ans[18]={2184,27829,27828,87890,87890,171054,171054,323510,127374,323510,151062,
151062,151062,151061,151060,151059,151058,7106718};
bool is[100010];
inline void mul(int x){
	for(int i=1;i<=len;i++) a[i]*=x;
	for(int i=1;i<=len;i++) if(a[i]>=B){
		a[i+1]+=a[i]/B;a[i]%=B;
		if(i==len) len++;
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
	n=read();a[1]=1,len=1;
	for(int i=2;i<=n;i++){
		if(!is[i]) prime[++cnt]=i;
		for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
			is[i*prime[j]]=1;
			if(i%prime[j]==0) break;
		}
	}
	if(n<=16) puts("No solution"),exit(0);
	if(n<=35) printf("%lld\n",ans[n-17]),exit(0);
	for(int i=sqrt(n);i<=n;i++) if(i*i>n){
		if(!is[i]&&!is[2*i+1]){A=i;break;}
	}
	mod=2*A*A+A,res=1;
	for(int i=1;i<=cnt;i++) if(prime[i]!=A&&prime[i]!=2*A+1) mul(prime[i]),res=res*prime[i]%mod;
	for(t=res,mu=1;t!=mod-3*A-1;t=(t+res)%mod,mu++);
	mul(mu);printf("%lld",a[len]);for(int i=len-1;i;i--) printf("%08lld",a[i]);
	return 0;
}

C. 小 G 的 DAG

动态维护不好搞于是根号分治一下

对于 \(1\) 操作,每根号次就更新一次

对于 \(2\) 操作,发现查询时只和上一次 \(1\) 操作后的值有关系

于是可以根号预处理一下,预处理操作完每个块之后的最小值

那么对于剩下的散块直接暴力查询

还剩下一个问题就是如何处理 \(x\) 能否到达 \(y\)

直接 \(bitset\) 开不下,于是可以每根号次操作处理一次,处理所有点能否到这根号次询问的点

Code
#include
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int B=500;
int n,m,Q;
int bl[100010],L[100010],R[100010];
int deg[100010],a[100010],p;
int head[100010],ver[100010],to[100010],tot;
int v[100010],lst[100010];
int mn[100010][210],id[100010],t[100010];
bool is[100010];
pairu[100010];
bitset<510>BT[100010];
queueq;
inline void add(int x,int y){ver[++tot]=y;to[tot]=head[x];head[x]=tot;}
struct opt{int op,u,x;}LL[100010];
inline void upd(){for(int i=1,x;i<=n;i++){x=a[i];v[x]=u[x].first;lst[x]=u[x].second;for(int j=head[x];j;j=to[j]){int y=ver[j];if(u[x].second>u[y].second) u[y]=u[x];}}}
inline void topo(){for(int i=1;i<=n;i++) BT[i].reset();for(int i=n,x;i;i--){x=a[i];if(is[x]) BT[x][id[x]]=1;for(int j=head[x];j;j=to[j]){int y=ver[j];BT[x]|=BT[y];}}}
inline void umn(int blo){for(int i=1,x;i<=n;i++){x=a[i];for(int j=head[x];j;j=to[j]){int y=ver[j];v[y]=min(v[y],v[x]);}}for(int i=1;i<=n;i++) mn[i][blo]=v[i];}
inline void pre(){
	for(int i=1;i<=bl[Q];i++){
		for(int j=1;j<=n;j++) v[j]=inf;
		for(int j=L[i];j<=R[i];j++) if(LL[j].op==2){
			v[LL[j].u]=min(v[LL[j].u],LL[j].x);
		}
		umn(i);
	}
}
inline int query(int x,int l,int r){
	int res=inf;
	if(bl[l]==bl[r]){
		for(int i=l;i<=r;i++) if(LL[i].op==2) if(BT[LL[i].u][id[x]]) res=min(res,LL[i].x);
		return res;
	}
	for(int i=l;i<=R[bl[l]];i++) if(LL[i].op==2) if(BT[LL[i].u][id[x]]) res=min(res,LL[i].x);
	for(int i=L[bl[r]];i<=r;i++) if(LL[i].op==2) if(BT[LL[i].u][id[x]]) res=min(res,LL[i].x);
	for(int i=bl[l]+1;i<=bl[r]-1;i++) res=min(res,mn[x][i]);
	return res;
}
inline int getv(int x,int l,int r){
	int res=v[x];
	for(int i=l;i<=r;i++) if(LL[i].op==1){if(BT[LL[i].u][id[x]]) res=LL[i].x,lst[x]=i;}
	return res;
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("dag.in","r",stdin);
	freopen("dag.out","w",stdout);
	n=read(),m=read(),Q=read();for(int i=1;i<=Q;i++) bl[i]=(i-1)/B+1;
	for(int i=1;i<=bl[Q];i++) L[i]=(i-1)*B+1,R[i]=min(i*B,Q);
	for(int i=1,x,y;i<=m;i++){x=read(),y=read();add(x,y);deg[y]++;}
	for(int i=1;i<=n;i++) if(!deg[i]) q.push(i);
	while(!q.empty()){
		int x=q.front();q.pop();a[++p]=x;
		for(int i=head[x];i;i=to[i]){
			int y=ver[i];deg[y]--;
			if(!deg[y]) q.push(y);
		}
	}
	for(int i=1;i<=Q;i++){LL[i].op=read(),LL[i].u=read();if(LL[i].op!=3) LL[i].x=read();}p=0;
	for(int i=L[1];i<=R[1];i++) if(LL[i].op==3) is[LL[i].u]=1,t[id[LL[i].u]=++p]=LL[i].u;
	topo();pre();
	for(int i=1;i<=n;i++) v[i]=0;
	for(int i=1,res;i<=Q;i++){
		if(LL[i].op==1) u[LL[i].u]=make_pair(LL[i].x,i);
		if(LL[i].op==3){
			res=getv(LL[i].u,L[bl[i]],i);
			res=min(res,query(LL[i].u,lst[LL[i].u],i));
			printf("%lld\n",res);
		}
		if(i==R[bl[i]]){
			for(int j=1;j<=p;j++) is[t[j]]=0;p=0;
			for(int j=L[bl[i]+1];j<=R[bl[i]+1];j++) if(LL[j].op==3) is[LL[j].u]=1,t[id[LL[j].u]=++p]=LL[j].u;
			topo();upd();
		}
	}
	return 0;
}