Code Chef JUNE Challenge 2019题解

题面

\(SUMAGCD\)

先去重,易知答案一定是一个数单独一组剩下的一组,前缀后缀\(gcd\)一下就行了

//quming
#include<bits/stdc++.h>
#define R register
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1e5+5;
int a[N],suf[N],Pre[N],n,T,mx;
int main(){
	for(scanf("%d",&T);T;--T){
		scanf("%d",&n),mx=0;
		fp(i,1,n)scanf("%d",&a[i]);
		sort(a+1,a+1+n),n=unique(a+1,a+1+n)-a-1;
		if(n==1){printf("%d\n",a[1]<<1);continue;}
		Pre[0]=0;fp(i,1,n)Pre[i]=__gcd(a[i],Pre[i-1]);
		suf[n+1]=0;fd(i,n,1)suf[i]=__gcd(suf[i+1],a[i]);
		fp(i,1,n)cmax(mx,a[i]+__gcd(Pre[i-1],suf[i+1]));
		printf("%d\n",mx);
	}
	return 0;
}

\(CHFING\)

\(1\)\(k-1\)肯定\(gg\),剩下的放到模\(k\)意义下,共有\(k\)个点,然后\(n-1\)条边,第\(i\)条边可以从\(c\)\((c+k+i)\%k\),设\(dis_c\)表示到\(c\)点的最短路,那么\(dis_c+p\times k\)都是能被标识的,剩下的不行。然后再仔细讨论一下就行了

//quming
#include<bits/stdc++.h>
#define R register
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
int T,res,p;ll n,k;
const int P=1e9+7;
inline int calc(R int x){return (1ll*x*(x+1)>>1)%P;}
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
	R int res=1;
	for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
	return res;
}
int main(){
	for(scanf("%d",&T);T;--T){
		scanf("%lld%lld",&n,&k),p=(k-1)/(n-1)%P,n%=P,k%=P;
		res=add(mul(calc(p),n-1),mul(p+1,dec(k-1,mul(p,n-1))));
		res=add(res,P);
		printf("%d\n",res);
	}
	return 0;
}

\(LENTMO\)

分情况讨论,如果\(k=n\)只有操作或不操作,如果\(k\)为奇数等价于\(k=1\),为偶数等价于\(k=2\)

//quming
#include<bits/stdc++.h>
#define R register
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
const int N=1e5+5;
int a[N],k,n,x,T;ll res,mx,sum[N];
int main(){
	for(scanf("%d",&T);T;--T){
		scanf("%d",&n),mx=res=0;
		fp(i,1,n)scanf("%d",&a[i]);
		scanf("%d%d",&k,&x);
		fp(i,1,n)res+=a[i],a[i]=(a[i]^x)-a[i];
		sort(a+1,a+1+n);sum[n+1]=0;
		fd(i,n,1)sum[i]=sum[i+1]+a[i];
		if(k==n)cmax(mx,sum[1]);
		else if(k&1)fp(i,1,n)cmax(mx,sum[i]);
		else for(R int i=n-1;i>0;i-=2)cmax(mx,sum[i]);
		printf("%lld\n",res+mx);
	}
	return 0;
}

\(INTRPATH\)

首先两条路径有交说明其中一个\(LCA\)在另一个上面。如果\((a,b)\)\((u,v)\)交于\(w\)上,\(w\)必定是\(LCA(a,b)\)\(LCA(u,v)\)

树剖,对于\(w\)\(LCA(a,b)\)的情况,每个节点上记录不同时经过\(u\)\(u\)的重儿子的简单路径的条数,然后做个前缀和。跳到另一条重链上的时候特殊处理一下,\(LCA\)上特殊处理一下

对于\(w\)\(LCA(u,v)\)的情况,计算一下跨过这棵子树的路径条数就可以了

//quming
#include<bits/stdc++.h>
#define R register
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
typedef long long ll;
const int N=3e5+5;
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int dfn[N],rk[N],sz[N],fa[N],dep[N],top[N],son[N];ll f[N],g[N],sum[N];
int n,tim,q,T;
inline void swap(R int &x,R int &y){R int t=x;x=y,y=t;}
void dfs1(int u){
	sz[u]=1,dep[u]=dep[fa[u]]+1,f[u]=1,son[u]=0;
	go(u)if(v!=fa[u]){
		fa[v]=u,dfs1(v),f[u]+=1ll*sz[v]*sz[u],sz[u]+=sz[v];
		if(sz[v]>sz[son[u]])son[u]=v;
	}
	g[u]=1ll*(sz[u]-sz[son[u]])*sz[son[u]],f[u]-=g[u];
}
void dfs2(int u,int t){
	top[u]=t,sum[dfn[u]=++tim]=f[u];
	if(!son[u])return;dfs2(son[u],t);
	go(u)if(v!=fa[u]&&v!=son[u])dfs2(v,v);
}
int jump(int u,int lca){
	int tmp=0;
	while(top[u]!=top[lca])tmp=top[u],u=fa[tmp];
	return sz[u==lca?tmp:son[lca]];
}
ll query(int u,int v){
	if(u==v)return f[u]+g[u]+1ll*sz[u]*(n-sz[u]);
	ll res=0;int x=u,y=v,lca,si;ll s;
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		u=fa[top[u]];
	}
	lca=dep[u]<dep[v]?u:v,u=x,v=y;
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		res+=sum[dfn[u]]-sum[dfn[top[u]]-1],u=top[u];
		if(fa[u]!=lca)res+=g[fa[u]]-1ll*sz[u]*(sz[fa[u]]-sz[u]);
		u=fa[u];
	}
	if(dep[u]<dep[v])swap(u,v);
	res+=sum[dfn[u]]-sum[dfn[v]];
	u=x,v=y,x=y=0;
	if(u!=lca)res+=g[u],x=jump(u,lca);
	if(v!=lca)res+=g[v],y=jump(v,lca);
	s=f[lca]+g[lca],si=sz[lca],s-=1ll*x*(si-x),si-=x,s-=1ll*y*(si-y);
	res+=s,res+=1ll*(sz[lca]-x-y)*(n-sz[lca]);
	return res;
}
inline void clr(){memset(head,0,(n+1)<<2),memset(fa,0,(n+1)<<2),tot=tim=0;}
int main(){
//	freopen("testdata.in","r",stdin);
	for(T=read();T;--T){
		n=read(),q=read();
		for(R int i=1,u,v;i<n;++i)u=read(),v=read(),add(u,v),add(v,u);
		dfs1(1),dfs2(1,1);
		fp(i,1,n)sum[i]+=sum[i-1];
		for(R int u,v;q;--q)u=read(),v=read(),printf("%lld\n",query(u,v));
		clr();
	}
	return 0;
}

\(COOLCHEF\)

某位大佬:复杂度算啥能过就行

简单来说就是用\(vector\)存下每个数的出现位置,然后每一个询问暴力二分就可以了……我也不知道为什么能过……唯一的剪枝就是把总共出现次数只有一次的去掉……

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=3e5+5,P=1e9+7;
inline void swap(R int &x,R int &y){R int t=x;x=y,y=t;}
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
	R int res=1;
	for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
	return res; 
}
vector<int>pos[N];int top,n,q,ans,m;
int fac[N],ifac[N],b[N],a[N],sz[N],bg[N],ed[N],st[N];
int main(){
//	freopen("testdata.in","r",stdin);
	n=read(),q=read();
	fp(i,1,n)a[i]=b[i]=read();
	fac[0]=ifac[0]=1;fp(i,1,n)fac[i]=mul(fac[i-1],i);
	ifac[n]=ksm(fac[n],P-2);fd(i,n-1,1)ifac[i]=mul(ifac[i+1],i+1);
	sort(b+1,b+1+n),m=unique(b+1,b+1+n)-b-1;
	fp(i,1,n)a[i]=lower_bound(b+1,b+1+m,a[i])-b,pos[a[i]].push_back(i);
	fp(i,1,m)if(pos[i].size()>1)
		st[++top]=i,bg[top]=pos[i].front(),ed[top]=pos[i].back();
	for(R int l1,l2,r1,r2,l,r,c;q;--q){
		l1=read(),l2=read(),r1=read(),r2=read();
		l=(1ll*l1*ans+l2)%n+1,r=(1ll*r1*ans+r2)%n+1;
		if(l>r)swap(l,r);
		ans=1;
		fp(i,1,top)if(bg[i]<=r&&ed[i]>=l){
			c=upper_bound(pos[st[i]].begin(),pos[st[i]].end(),r)
			 -lower_bound(pos[st[i]].begin(),pos[st[i]].end(),l);
			ans=mul(ans,ifac[c]);
		}
		ans=mul(ans,fac[r-l+1]);
		printf("%d\n",ans);
	}
	return 0;
}

\(COUNTIT\)

为了方便把前\(n\)个数记为\(a_i\),后\(m\)个数记为\(b_i\)

可以证明,当且仅当\(\max(a_i)=\max(b_i)\)一定是一组合法解(如果不想看证明的可以直接跳过)

必要性很显然。对于充分性,假设\(a_i\)\(b_i\)的最大值都只有一个,那么把除了这一行一列之外的其他数都设为\(1\),这一行一列的数调整到满足对应行列的需求。如果有多个最大值同理

所以答案就是

\[\sum_{i=1}^k\left(i^n-(i-1)^n\right)(i^m-(i-1)^m) \]

后面展开是一个\(n+m\)次多项式,前缀和是一个\(n+m+1\)次多项式,拉格朗日插值就行了

代码还没调出来再等等

好吧原来是拉格朗日插值打错了……

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
const int P=1e9+7;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
    R int res=1;
    for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
    return res;
}
const int N=5e5+5;
int fn[N],fm[N],f[N],fac[N],ifac[N],Pre[N],suf[N],n,m,p,T,c;
int Lagrange(int n,int k){
	if(k<=n)return f[k];
	Pre[0]=1;fp(i,1,n)Pre[i]=mul(Pre[i-1],k-i);
	suf[n+1]=1;fd(i,n,1)suf[i]=mul(suf[i+1],k-i);
	int res=0,ty=(n&1)?1:P-1;
	fp(i,1,n)upd(res,1ll*f[i]*ty%P*Pre[i-1]%P*suf[i+1]%P*ifac[i-1]%P*ifac[n-i]%P),ty=P-ty;
	return res;
}
int main(){
//	freopen("testdata.in","r",stdin);
	int t=2e5+10;
	fac[0]=ifac[0]=1;fp(i,1,t)fac[i]=mul(fac[i-1],i);
	ifac[t]=ksm(fac[t],P-2);fd(i,t-1,1)ifac[i]=mul(ifac[i+1],i+1);
	for(scanf("%d",&T);T;--T){
		scanf("%d%d%d",&n,&m,&p),c=n+m+5;
		fn[0]=fm[0]=0;
		fp(i,1,c)fn[i]=ksm(i,n);
		fp(i,1,c)fm[i]=ksm(i,m);
		fp(i,1,c)f[i]=mul(dec(fn[i],fn[i-1]),dec(fm[i],fm[i-1]));
		fp(i,1,c)upd(f[i],f[i-1]);
		printf("%d\n",Lagrange(c,p));
	}
}

\(FGTREE\)

七月月赛都开了我才补完六月的……

我们对于\(dfs\)序从小到大考虑,维护一个栈,表示的是从根节点到当前节点的这条链,对于新的节点,如果还在这条链上就加入,否则说明之前有一些节点可以出栈了,那么就可以顺便更新左边界和他们的父亲

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
const int N=105;
int fa[N],l[N],st[N],top,n,T;
bool ask(int x,int l,int r){
	printf("Q %d %d %d\n",x,l,r),fflush(stdout);
	char s[5];scanf("%s",s);return s[0]=='Y'; 
} 
int main(){
	for(scanf("%d",&T);T;--T){
		scanf("%d",&n),top=0;
		memset(fa,-1,(n+1)<<2);
		fp(i,1,n){
			int las=0;
			while(top&&ask(st[top],l[st[top]],i-1)){
				if(las)fa[las]=st[top];
				las=st[top--];
			}
			las?(fa[las]=i,l[i]=l[las]):l[i]=i;
			st[++top]=i;
		}
		while(top>1)fa[st[top]]=st[top-1],--top;
		putchar('A');
		fp(i,1,n)printf(" %d",fa[i]);
		puts(""),fflush(stdout);
	}
	return 0;
}
posted @ 2019-07-01 21:43  源曲明  阅读(324)  评论(0编辑  收藏  举报