Code Chef February Challenge 2019题解

传送门

(HMAPPY2)

话说这题居然卡(scanf)的么???

int T;cin>>T;
while(T--){
	cin>>n>>a>>b>>k;
	puts(n/a+n/b-n/(a*b/__gcd(a,b))*2>=k?"Win":"Lose");
}

(CHEFING)

咕咕

int T;scanf("%d",&T);
while(T--){
	scanf("%d",&n),res=0;
	fp(i,0,25)flag[i]=1;
	while(n--){
		scanf("%s",s+1);
		fp(i,0,25)cnt[i]=0;
		fp(i,1,strlen(s+1))cnt[s[i]-'a']=1;
		fp(i,0,25)flag[i]&=cnt[i];
	}
	fp(i,0,25)res+=flag[i];
	printf("%d
",res);
}

(DEPCHEF)

咕咕咕

int T;scanf("%d",&T);
while(T--){
	scanf("%d",&n),mx=-1;
	fp(i,1,n)scanf("%d",&a[i]);a[0]=a[n],a[n+1]=a[1];
	fp(i,1,n)scanf("%d",&d[i]);d[0]=d[n],d[n+1]=d[1];
	fp(i,1,n)if(a[i-1]+a[i+1]<d[i])cmax(mx,d[i]);
	printf("%d
",mx);
}

(MAGICJAR)

咕咕咕咕

int T;scanf("%d",&T);
while(T--){
	scanf("%d",&n),res=0;
	fp(i,1,n)scanf("%d",&a[i]),res+=a[i]-1;
	printf("%lld
",res+1);
}

(ARTBALAN)

发现只与字母出现次数有关。枚举一下最后剩下(k)个字母,那么每种字母要剩(n/k)个,如果不选代价是(cnt_i),选了代价是(|cnt_i-n/k|),先假设全选,再找出(|cnt_i-n/k|-cnt_i)最小的(k)个加上就是了

//minamoto
#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 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;
}
int read(char *s){
	R int len=0;R char ch;while(((ch=getc())>'Z'||ch<'A'));
	for(s[++len]=ch;(ch=getc())>='A'&&ch<='Z';s[++len]=ch);
	return s[len+1]='',len;
}
const int N=1e6+5;
char s[N];int cnt[35],a[35],res,tmp,n;
inline int abs(R int x){return x<0?-x:x;}
int main(){
//	freopen("testdata.in","r",stdin);
	for(int T=read();T;--T){
		n=read(s),res=n+1;
		memset(cnt,0,104);
		fp(i,1,n)++cnt[s[i]-'A'];
		fp(k,1,26)if(n%k==0){
			tmp=0;
			fp(i,0,25)tmp+=cnt[i],a[i]=abs(n/k-cnt[i])-cnt[i];
			sort(a,a+26);
			fp(i,0,k-1)tmp+=a[i];
			cmin(res,tmp>>1);
		}
		printf("%d
",res);
	}
	return 0;
}

(MANRECT)

先询问((0,0)),可以求出矩形左下角所在的那条副对角线,同理询问((0,inf),(inf,inf),(inf,0)),然后再求出左上角的对角线和右上角的对角线的交点横坐标(x)(有可能不是整数,那么下取整),此时询问((x,inf)),得到的必然是矩形上边界离(y=inf)这条直线的距离,然后就求出矩形右上角的(y)坐标了,剩下的代入方程就可以了

话说为啥用(scanf)(printf)(T)啊???

//minamoto
#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)
using namespace std;
int read(){
    R int res,f=1;R char ch;
    while((ch=getchar())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getchar())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
inline int print(R int x,R int y){cout<<'Q'<<' '<<x<<' '<<y<<endl;fflush(stdout);return read();}
const int inf=1e9;
int a,b,c,d,t,x,y,xx,yy;
int main(){
//	freopen("testdata.in","r",stdin);
	int T=read();
	while(T--){
		a=print(0,0),b=print(0,inf),c=print(inf,inf),d=print(inf,0);
		if(0ll+b+c<inf)t=print(b+1,inf);else t=print((0ll+inf+b-c)>>1,inf);
		yy=0ll+inf-t,xx=0ll+(inf<<1)-c-yy;
		y=0ll+xx-inf+d,x=0ll+a-y;
		cout<<'A'<<' '<<x<<' '<<y<<' '<<xx<<' '<<yy<<endl;
		fflush(stdout);
		read();
	}
	return 0;
}

(GUESSRT)

最优策略应该是先排除最后一个不管,前面一直(12121212...),最后一个必选(1)

证明的话……我瞎猜的一个结论你叫我证明……

顺便注意如果刚开始(n>k)要先进行一次(2)操作令(nleq k)

upd:去看了看官方题解,这个似乎应该反过来说,也就是如果只剩一个选(1),前面一直按照(21212121)的顺序,因为(21)的概率显然比(11)要大

//minamoto
#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)
using namespace std;
int read(){
    R int res,f=1;R char ch;
    while((ch=getchar())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getchar())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=6e4+5,P=1e9+7;
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 n,m,k,res,tmp,inv[N];
int main(){
//	freopen("testdata.in","r",stdin);
	inv[0]=inv[1]=1;fp(i,2,N-1)inv[i]=mul(P-P/i,inv[P%i]);
	for(int T=read();T;--T){
		n=read(),k=read(),m=read();
		if(m==1){printf("%d
",inv[n]);continue;}
		if(n>k)--m,n=(n-1)%k+1;
		tmp=ksm(mul(n-1,inv[n]),(m+1)>>1);
		res=add(P+1-tmp,(m&1^1)?mul(tmp,inv[n+k]):0);
		printf("%d
",res);
	}
	return 0;
}

(CHORCKIT)

咕咕咕咕咕咕咕咕咕

(challenge)不写了

(XDCOMP)

首先对于一个子树,只有它的异或和为(x)(0)才有分割成功的可能

我们记(f_{u,0/1})表示对于(u)这棵子树,已经割掉的边为偶数/奇数的方案数,转移的时候,如果当前这条边不割,那么直接转移就是。只有当(sum_v)(其中(sum)表示子树异或和)为(0)(v)的子树里割掉的边为奇数条,或者(sum_v)(x)(v)的子树里割掉的边为偶数条,这一条边才允许被割掉。最后记得判一下整棵树的异或和

//minamoto
#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)
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=1e5+5,P=1e9+7;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:x;}
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;
}
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 f[N][2],g[N][2],sum[N],n,x,res;
void dfs(int u,int fa){
	f[u][0]=1,f[u][1]=0;
	go(u)if(v!=fa){
		dfs(v,u),sum[u]^=sum[v];
		g[u][0]=g[u][1]=0;
		if(sum[v]==x){
			upd(g[u][1],mul(f[u][0],f[v][0])),
			upd(g[u][0],mul(f[u][1],f[v][0]));
		}
		if(sum[v]==0){
			upd(g[u][1],mul(f[u][1],f[v][1])),
			upd(g[u][0],mul(f[u][0],f[v][1]));
		}
		upd(g[u][0],mul(f[u][0],f[v][0])),
		upd(g[u][0],mul(f[u][1],f[v][1])),
		upd(g[u][1],mul(f[u][0],f[v][1])),
		upd(g[u][1],mul(f[u][1],f[v][0]));
		f[u][0]=g[u][0],f[u][1]=g[u][1];
	}
}
int main(){
//	freopen("testdata.in","r",stdin);
	n=read(),x=read();
	fp(i,1,n)sum[i]=read();
	for(R int i=1,u,v;i<n;++i)u=read(),v=read(),Add(u,v),Add(v,u);
	dfs(1,0);
	if(sum[1]==x)upd(res,f[1][0]);
	if(sum[1]==0)upd(res,f[1][1]);
	printf("%d
",res);
	return 0;
}

(MAXTAX)

缩点之后跑个(dp)就可以了

关于同一个联通块内,我们可以先(sort)一下,然后枚举有(i)个人会因为税款太高而愉悦,那么能收到的最大税款就是((cnt-i) imes b_{i+1})

记得要求的是最大值,计算过程中不需要取模

清零的时候我忘了(long long)(8)个字节然后计算的时候算错了orz

//minamoto
#include<bits/stdc++.h>
#define R register
#define pb push_back
#define ll long long
#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 cmin(T&a,const T&b){return a>b?a=b,1:0;}
template<class T>inline bool cmax(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;
}
const int N=2e5+5,M=5e5+5,P=1e9+21;
struct eg{int v,nx;}e[M];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
vector<int>to[N],nod[N];int col[N],dfn[N],low[N],st[N],deg[N],top,cnt,tim;
int q[N],a[N];ll f[N][205],tmp[205],res;
void tarjan(int u){
	dfn[u]=low[u]=++tim,st[++top]=u;
	for(R int i=0,s=to[u].size(),v;i<s&&(v=to[u][i]);++i)
		if(!dfn[v])tarjan(v),cmin(low[u],low[v]);
		else if(!col[v])cmin(low[u],dfn[v]);
	if(low[u]==dfn[u])
		for(++cnt,st[top+1]=0;st[top+1]!=u;--top)
			col[st[top]]=cnt,nod[cnt].pb(a[st[top]]);
}
int n,m,k;
void clr(){
	fp(i,1,n)vector<int>().swap(to[i]);
	fp(i,1,cnt)vector<int>().swap(nod[i]);
	memset(col,0,(n+1)<<2),memset(dfn,0,(n+1)<<2);
	memset(deg,0,(cnt+1)<<2),memset(head,0,(cnt+1)<<2);
	tot=cnt=top=tim=0;
}
void solve(){
	int h=1,t=0,u;++cnt;
	fp(i,1,cnt-1){
		add(i,cnt),++deg[cnt];
		if(!deg[i])q[++t]=i;
		memset(f[i],0,(k+1)<<3);
	}
	memset(f[cnt],0,(k+1)<<3);
	while(h<=t){
		u=q[h++],sort(nod[u].begin(),nod[u].end());
		fp(j,0,k)tmp[j]=f[u][j];
		for(R int i=0,s=nod[u].size();i<s;++i)
			fp(j,0,k-i)cmax(tmp[i+j],f[u][j]+1ll*(s-i)*nod[u][i]);
		go(u){
			fp(j,0,k)cmax(f[v][j],tmp[j]);
			if(!--deg[v])q[++t]=v;
		}
	}
}
int main(){
//	freopen("testdata.in","r",stdin);
	for(int T=read();T;--T){
		n=read(),m=read(),k=read();
		fp(i,1,n)a[i]=read();
		for(R int i=1,u,v;i<=m;++i)u=read(),v=read(),to[u].pb(v);
		fp(i,1,n)if(!dfn[i])tarjan(i);
		fp(u,1,n)for(R int i=0,s=to[u].size(),v;i<s&&(v=to[u][i]);++i)
			if(col[u]!=col[v])add(col[u],col[v]),++deg[col[v]];
		solve();
		res=0;
		fp(i,0,k)cmax(res,f[cnt][i]);
		printf("%lld
",res%P);
		clr();
	}
	return 0;
}

(TRDST)

我怎么又把点分给忘了→_→

首先在每一个点处是可以二分答案的,那么我们现在的问题转化为求到它的距离大于(mid)的点数,也可以转化为数到它的距离小于等于(mid)的点数

到某个顶点距离小于等于(k)的点数……这就是个点分树的经典应用了,我觉得代码比我讲得清楚所以建议自行看代码理解

//minamoto
#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;}
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;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
    if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]=' ';
}
const int N=1e5+5,M=3e6+5;
inline int min(R int x,R int y){return x<y?x:y;}
int pool[M],*pp=pool;
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;}
struct Eg{int sz,nx,d,sgn,*c;}E[M];int Head[N],tc;
int sz[N],mx[N],dep[N],fa[N],q[N],vis[N],size,rt;
int n,a[N];
void findrt(int u,int fa){
	sz[u]=1,mx[u]=0;
	go(u)if(v!=fa&&!vis[v])findrt(v,u),sz[u]+=sz[v],cmax(mx[u],sz[v]);
	cmax(mx[u],size-sz[u]);
	if(mx[u]<mx[rt])rt=u;
}
void dfs(int u,int sgn,int d){
	int h=1,t=0;q[++t]=u,dep[u]=d,fa[u]=0;
	while(h<=t){
		u=q[h++],++pp[dep[u]];
		go(u)if(!vis[v]&&v!=fa[u])q[++t]=v,dep[v]=dep[u]+1,fa[v]=u;
	}
	int len=dep[q[t]];
	fp(i,1,t)u=q[i],E[++tc]={len,Head[u],dep[u],sgn,pp},Head[u]=tc;
	fp(i,1,len)pp[i]+=pp[i-1];
	pp+=len+1;
}
void solve(int u){
	vis[u]=1,dfs(u,1,0);
	int s=size;
	go(u)if(!vis[v]){
		dfs(v,-1,1);
		rt=0,size=sz[v]>sz[u]?s-sz[u]:sz[v],findrt(v,0);
		solve(rt);
	}
}
int calc(int d,int u){
	int res=0;
	for(R int i=Head[u];i;i=E[i].nx)
		if(d>=E[i].d)res+=E[i].c[min(d-E[i].d,E[i].sz)]*E[i].sgn;
	return n-res;
}
int main(){
//	freopen("testdata.in","r",stdin);
	n=read();
	fp(i,1,n)a[i]=read();
	for(R int i=1,u,v;i<n;++i)u=read(),v=read(),add(u,v),add(v,u);
	mx[0]=n+1,rt=0,size=n,findrt(1,0),solve(rt);
	int l,r,mid,ans;
	fp(i,1,n){
		l=0,r=n-1;
		while(l<=r)mid=(l+r)>>1,(calc(mid,i)>=a[i])?(ans=mid,l=mid+1):r=mid-1;
		print(ans);
	}
	return Ot(),0;
}
原文地址:https://www.cnblogs.com/bztMinamoto/p/10721322.html