[Contest] BC Round #79

可以打div1了,感谢带我飞的神犇ZZY

不熟悉莫比乌斯,T4没打出来,一直在给暴力调常数


A


懒得推了,乱搞,暴力枚举好了


#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

int main()
{
	int Q,n,m;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(Q);
	while (Q--)
	{
		read(n); read(m);
		int flag=0;
		for (int x=0;x<=360 && !flag;x++)
			for (int y=0;y<=360 && !flag;y++)
				if ((180*n-360)*m*x+(180*m-360)*n*y==360*n*m)
					flag=1;
		if (flag)
			printf("Yes\n");
		else
			printf("No\n");
	}
	
	return 0;
}



B


考虑从高位到低位贪心,对于每一位,如果x,y只有唯一的取法,那么只能这么取;否则贪心地必须使答案的这一位等于1。如果x,y都是0,1都能取,则设这是从右向左数第len位,因为x,y能取的值一定都是连续的一段,因此x,y的后len位都能取0111...1(len-1个1)和1000...0(len-1个0)(否则做不到从右向左数第len位都能取0,1)。也就是说,后len位的贡献一定能达到可能的上界111...1(len个1)。此时不必继续考虑后面的位。

如果x,y在这一位并不是0,1都能取,那么由于要使得答案的这一位等于1,也只有唯一的取法。

至此,这一位考虑完毕,然后根据选取的方案,修正一下x和y的范围,然后对后一位做即可。


#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(ll &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

ll a,b,c,d;

int main()
{
	#define MC 63
	ll Q;
	int x1,x2,y1,y2;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(Q);
	while (Q--)
	{
		ll ans=0;
		read(a); read(b); read(c); read(d);
		for (int i=MC;i>=0;i--)
		{
			x1=(bool)(a&(1LL<<i)); x2=(bool)(b&(1LL<<i));
			y1=(bool)(c&(1LL<<i)); y2=(bool)(d&(1LL<<i));
			if (x1==x2 && y1==y2)
			{
				if (x1!=y1)
					ans+=1LL<<i;
			}
			else if (x1!=x2 && y1==y2)
			{
				ans+=1LL<<i;
				if (y1==1)
				{
					a=a;
					b=(1LL<<i)-1;
				}
				else if (y1==0)
				{
					a=(1LL<<i);
					b=b;
				}
			}
			else if (y1!=y2 && x1==x2)
			{
				ans+=1LL<<i;
				if (x1==1)
				{
					c=c;
					d=(1LL<<i)-1;
				}
				else if (x1==0)
				{
					c=(1LL<<i);
					d=d;
				}
			}
			else if (y1!=y2 && x1!=x2)
			{
				ans+=(1LL<<(i+1))-1;
				break;
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}


C


枚举K 然后就是一个单调栈维护成为最小值向左向右能延生的最长距离

调和级数 复杂度 O(n ln n)


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

int n,a[300005];
int height[300005],cnt;
ll sum[300005];
int l[300005],r[300005];
int Stack[300005],pnt;

int main()
{
	#define MC 63
	int Q;
	ll ans;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(Q);
	while (Q--)
	{
		read(n); ans=0; 
		for (int i=1;i<=n;i++)
			read(a[i]);
		for (int k=1;k<=n;k++)
		{
			cnt=0;
			for (int j=1;j*k<=n;j++)
				height[++cnt]=a[j*k];
			for (int i=1;i<=cnt;i++)
				sum[i]=sum[i-1]+height[i];
			height[0]=-1<<30; 
			height[cnt+1]=-1<<30;
			pnt=0;
			Stack[++pnt]=0;
			for (int i=1;i<=cnt;i++)
			{
				while (height[Stack[pnt]]>=height[i]) Stack[pnt--]=0;
				if (Stack[pnt]==0) l[i]=1; else l[i]=Stack[pnt]+1;
				Stack[++pnt]=i;
			}
			pnt=0;
			Stack[++pnt]=cnt+1;
			for (int i=cnt;i;i--)
			{
				while (height[Stack[pnt]]>height[i]) Stack[pnt--]=0;
				if (Stack[pnt]==n+1) r[i]=n; else r[i]=Stack[pnt]-1;
				Stack[++pnt]=i;
			}
			for (int i=1;i<=cnt;i++)
				ans=max(ans,(sum[r[i]]-sum[l[i]-1])*height[i]*(ll)sqrt(k));
		}
		printf("%I64d\n",ans);
	}
	return 0;
}



实际上我并不熟悉莫比乌斯一套理论,%%Hillan

上官方题解


不妨令n\leq mnm

对于这一题,我们可以将所求的有多少对正整数对的最大公约数不为完全平方数转化为有多少对最大公约数为完全平方数。

那么我们设函数F\left(x\right)F(x),当且仅当xx为完全平方数时函数值为1,否则函数值为0。那么

Ans=\sum_{i=1}^n\sum_{j=1}^mF\left(\gcd\left(i,j\right)\right)Ans=i=1nj=1mF(gcd(i,j)) 设d=\gcd\left(i,j\right)d=gcd(i,j),那么

Ans=\sum_{i=1}^n\sum_{j=1}^mF\left(d\right)Ans=i=1nj=1mF(d)。 然后我们推一下这个式子:

Ans=\sum_{d=1}^nF\left(d\right)\times\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\left[\gcd\left(i,j\right)=1\right]Ans=d=1nF(d)×i=1dnj=1dm[gcd(i,j)=1]

=\sum_{d=1}^nF\left(d\right)\times\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{t|i,t|j}\mu\left(t\right) =\sum_{d=1}^nF\left(d\right)\times\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\mu\left(t\right)\times\lfloor\frac{n}{dt}\rfloor\times\lfloor\frac{m}{dt}\rfloor=d=1nF(d)×i=1dnj=1dmti,tjμ(t)=d=1nF(d)×i=1dnμ(t)×dtn×dtm 然后我们设G=dtG=dt,则Ans=\sum_{G=1}^n\left(t\right)\times\lfloor\frac{n}{G}\rfloor\times\lfloor\frac{m}{G}\rfloor\times\sum_{t|G}\mu\left(t\right)\times F\left(\frac{G}{t}\right)Ans=G=1nGn×Gm×tGμ(t)×F(tG) 然后我们设g(x)=\sum_{t|x}\mu\left(t\right)\times F\left(\frac{x}{t}\right)g(x)=txμ(t)×F(tx),则Ans=\sum_{G=1}^n\left(t\right)\times\lfloor\frac{n}{G}\rfloor\times\lfloor\frac{m}{G}\rfloor\times g(G)Ans=G=1nGn×Gm×g(G)

那么这道题的解法就出来了,如果我们已经确定gg函数的前缀和,那么就只需要类似莫比乌斯反演的方法O\left(\sqrt{n}\right)O(n)算一下即可。

g么,暴力算一下好了


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x){
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int M=10000000;
int n,m;
ll sum[M+5];
int prime[5000005],num;
int mobius[M+5],vst[M+5];

inline void Pre()
{
	const int maxn=M;
	mobius[1]=1;
	for (int i=2;i<=maxn;i++)
	{
		if (!vst[i])
			mobius[i]=-1,prime[++num]=i;
		for (int j=1;j<=num && prime[j]*i<=maxn;j++)
		{
			vst[i*prime[j]]=1;
			if (i%prime[j]==0)
			{
				mobius[prime[j]*i]=0; break;
			}
			else
				mobius[prime[j]*i]=-mobius[i];
		}
	}
	int maxi=sqrt(maxn);
    for (int i=1;i<=maxi;i++)
	{
        int step=i*i;
        for(int tmp=step,j=1;tmp<=maxn;tmp+=step,j++)
			if(mobius[j])
				sum[tmp]+=mobius[j];
    }
    for (int i=1;i<=maxn;i++)
		sum[i]+=sum[i-1];
}

inline ll Solve(int n,int m)
{
	if (n>m) swap(n,m);
	ll ret=0;
	for (int i=1,j;i<=n;i=j+1)
	{
		j=min(n/(n/i),m/(m/i));
		ret+=(ll)(n/i)*(m/i)*(sum[j]-sum[i-1]);
	}
	return ret;
}


int main()
{
	int Q;
	ll ans;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	Pre();
	read(Q);
	while (Q--)
	{
		read(n); read(m);
		ans=(ll)n*m;
		ans-=Solve(n,m);
		printf("%lld\n",ans);
	}
	return 0;
}


E


二分加点分治 莫名其妙调了一下午...

sort啊,重心啊,可以预处理,这样每次check就是O(nlogn)


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cstring>
#define V G[p].v
#define cl(x) memset(x,0,sizeof(x))
using namespace std;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

struct edge{
	int u,v,w;
	int next;
};

edge G[100005];
int head[50005],inum;

inline void add(int u,int v,int w,int p){
	G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}

int n,m,K;

int sum,minimum,rt;
int size[50005],del[50005];

int ans,Mid;

int A[2000005],pnt;
int ls[2000005],rs[2000005],clk;
int Rt[50005],tik;

inline void Root(int u,int fa){
	size[u]=1;
	int maximum=0;
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa && !del[V])
			Root(V,u),size[u]+=size[V],maximum=max(maximum,size[V]);
	maximum=max(maximum,sum-size[u]);
	if (minimum>maximum) minimum=maximum,rt=u;
}

namespace Pre{
	int a[50005],cnt;
	inline void Calc(int *a,int s,int t)
	{
		++clk;
		ls[clk]=pnt+1;
		for (int i=s;i<=t;i++) A[++pnt]=a[i];
		rs[clk]=pnt;
		sort(A+ls[clk],A+rs[clk]+1);
	}
	inline void dfs(int u,int fa,int dis)
	{
	    a[++cnt]=dis;
	    for (int p=head[u];p;p=G[p].next)
	        if (V!=fa && !del[V])
	            dfs(V,u,dis+G[p].w);
	}
	inline void Solve(int u)
	{
	    del[u]=1; cnt=0;
	    int last=cnt;
	    for (int p=head[u];p;p=G[p].next)   
	        if (!del[V])
	        {
	            dfs(V,u,G[p].w);
	            Calc(a,last+1,cnt);
	            last=cnt;
	        }
	    a[++cnt]=0;
	    Calc(a,1,cnt);
	    for (int p=head[u];p;p=G[p].next)
	        if (!del[V])
	        {
	            sum=size[V]; minimum=1<<30; Root(V,0); Rt[++tik]=rt;
	            Solve(rt);
	        }
	}
	inline void Work(){
		cl(del); clk=tik=0;
		sum=n; minimum=1<<30; Root(1,0); Rt[++tik]=rt;
		Solve(rt);
	}
}

inline int Calc()
{
	++clk;
	int s=ls[clk],t=rs[clk];
    int ret=0;
    int l=s,r=t+1;
    while (r-1>l && A[r-1]+A[l]>=Mid) r--;
    ret+=t-r+1;
    for (l++;l<=t;l++)
    {
    	r=max(r,l+1);
        while (r-1>l && A[r-1]+A[l]>=Mid) r--;
        ret+=t-r+1;
    }
    return ret;
}

inline void Solve(int u)
{
    del[u]=1;
    for (int p=head[u];p;p=G[p].next)   
        if (!del[V])
            ans-=Calc();
    ans+=Calc();
    for (int p=head[u];p;p=G[p].next)
        if (!del[V])
            Solve(Rt[++tik]);
}

int D[50005],icnt,iter;

inline void DEl(int u,int fa,int d){
	int last=iter;
	D[++icnt]=d;
	while (iter+1<=icnt && D[icnt]-D[iter]>=Mid) iter++;
	ans-=iter-1;
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
			DEl(V,u,d+G[p].w);
	D[icnt--]=0;
	iter=last;
}

inline bool check(int mid){
	Mid=mid; ans=0; 
	cl(del); clk=tik=0;
	Solve(Rt[++tik]);
	icnt=0; iter=1; DEl(m,0,0);
	return ans>=K;
}

int maxd;

inline void dfs(int u,int fa,int d){
	maxd=max(maxd,d);
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
			dfs(V,u,d+G[p].w);
}

int main()
{
	int Q,iu,iv,iw;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(Q);
	while (Q--)
	{
		read(n); read(m); read(K);
		for (int i=1;i<n;i++) read(iu),read(iv),read(iw),add(iu,iv,iw,++inum),add(iv,iu,iw,++inum);
		Pre::Work();
		maxd=0;
		dfs(m,0,0);
		int L=1,R=(maxd<<1)+1,MID;
		if (!check(0))
		{
			printf("NO\n");
			goto W;
		}
		while (L+1<R)
			if (check(MID=(L+R)>>1))
				L=MID;
			else
				R=MID;
		printf("%d\n",L);
W:		inum=0; cl(G); cl(head); pnt=0; 
	}
	return 0;
}




你可能感兴趣的:([Contest] BC Round #79)