其他分享
首页 > 其他分享> > COMPFEST 14 - Preliminary Online Mirror(持续更新)

COMPFEST 14 - Preliminary Online Mirror(持续更新)

作者:互联网

Preface

9/10:今天不知道为什么一整天头疼的一批,而且牙也疼的吃不了饭,实在写不动题目啊

9/11:晚上发烧了,结果睡了一晚竟然好了……我的自愈能力原来这么强的嘛awa

9/12:得知错过了校队的第一轮选拔(没收到通知qaq),得等大一下才有机会了

不过自己写写题也比较轻松没什么压力,但接下来得准点打比赛了不能天天VP

下面题目做的顺序排,大致是按难度递增的把


A. Accumulation of Dominoes

SB题,注意特判\(m=1\)的情形

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
int n,m;
int main()
{
	scanf("%d%d",&n,&m); if (m==1) return printf("%d",n-1),0;
	return printf("%lld",1LL*n*(m-1)),0;
}

B. Basketball Together

SB题,贪心地从大到小考虑每个人为队长,拉队员的话就从小的开始拉

#include<cstdio>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int n,d,a[N],ans;
int main()
{
	RI i,j; for (scanf("%d%d",&n,&d),i=1;i<=n;++i) scanf("%d",&a[i]);
	for (++d,sort(a+1,a+n+1),i=0,j=n;i<j;--j)
	{
		int k=(d-1)/a[j]; if (i+k<j) i+=k,++ans; else break;
	}
	return printf("%d",ans),0;
}

G. Garage

貌似之前有过哪个题目有这个结论的说

直接说结论,\(x\)是合法的当且仅当\(x\)是大于等于\(3\)的奇数大于等于\(8\)的\(4\)的倍数

证明,若\(x=2k+1,k\ge 1\),显然当\(b=k+1,a=k\)时符合,若\(x=4k+4,k\ge 1\),显然当\(b=k+2,a=k\)时符合

那么剩下来不符合的就是形如\(4k+2,k\ge 1\)的数了,不难发现由于\(a^2.b^2\)对\(4\)取模后的结果要么是\(0\)要么是\(1\),因此\(b^2-a^2\)对\(4\)取模的结果必不可能是\(2\)

计算答案的话可以直接二分,求\(\le x\)中有多少个合法的数即可

#include<cstdio>
#include<iostream>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
int n,ans;
inline int count(CI x)
{
	return (x+1)/2-1+(x>=4?x/4-1:0);
}
signed main()
{
	scanf("%lld",&n); int l=3,r=2147483647,mid;
	while (l<=r)
	{
		mid=l+r>>1; if (count(mid)>=n) ans=mid,r=mid-1; else l=mid+1;
	}
	return printf("%lld",ans),0;
}

M. Moving Both Hands

一个朴素的想法,设\(d(x,y)\)表示\(x\)到\(y\)的最短路,考虑枚举中间点,对于\((1,v)\)的答案就是\(\min_\limits{1\le i\le n} d(1,i)+d(v,i)\)

将原图中的边反向,设\(d'(x,y)\)表示反向图中\(x\)到\(y\)的最短路,此时答案为\(\min_\limits{1\le i\le n} d(1,i)+d'(i,v)\)

考虑对每个点增加一个状态,设\((x,0/1)\)表示到\(x\)的最短路,第二维表示是否反向,此时有:

这样直接跑一遍Dijkstra即可,最后点\(v\)的答案就是\((1,0)\)到\((v,1)\)的最短路

#include<cstdio>
#include<queue>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
const long long INF=1e18;
struct edge
{
	int to,nxt,v;
}e[N<<2]; int n,m,head[N],cnt,x,y,z; long long dis[N]; bool vis[N];
struct data
{
	long long v; int p;
	inline data(const long long& V=0,CI P=0) { v=V; p=P; }
	friend inline bool operator < (const data& A,const data& B)
	{
		return A.v>B.v;
	}
}; priority_queue <data> hp;
inline void addedge(CI x,CI y,CI z)
{
	e[++cnt]=(edge){y,head[x],z}; head[x]=cnt;
}
#define to e[i].to
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i; for (scanf("%d%d",&n,&m),i=1;i<=m;++i)
	scanf("%d%d%d",&x,&y,&z),addedge(x,y,z),addedge(n+y,n+x,z);
	for (i=1;i<=n;++i) addedge(i,n+i,0);
	for (i=1;i<=(n<<1);++i) dis[i]=INF; dis[1]=0;
	hp.push(data(dis[1],1)); while (!hp.empty())
	{
		int now=hp.top().p; hp.pop(); if (vis[now]) continue; vis[now]=1;
		for (i=head[now];i;i=e[i].nxt) if (dis[to]>dis[now]+e[i].v)
		hp.push(data(dis[to]=dis[now]+e[i].v,to));
	}
	for (i=2;i<=n;++i) printf("%lld ",dis[n+i]!=INF?dis[n+i]:-1);
	return 0;
}

C. Circular Mirror

首先不难发现存在直角三角形的充要条件是:存在某个颜色,其颜色点数大于等于\(3\)且其中的两点恰好在一直径上

首先我们可以扫一遍求出一共有多少对点对在一直径上,记为\(cnt\),剩下的自由点记为\(left=n-cnt*2\)

考虑枚举恰好有多少对直径点对的颜色相同,记为\(i\),那么此时的贡献即为:

\[C_{cnt}^i\times C_m^i\times i!\times [(m-i)\times (m-i-1)]^{cnt-i}\times (m-i)^{left} \]

首先前面的\(C_{cnt}^i\times C_m^i\times i!\)表示从\(cnt\)个点对中选出\(i\)对并且找出\(i\)种颜色一一匹配的方案数,\([(m-i)\times (m-i-1)]^{cnt-i}\)表示剩余的\(cnt-i\)个点对的选法(此时两两颜色不同),\((m-i)^{left}\)表示剩下的自由点的选法

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=300005,mod=998244353;
int n,m,a[N],cnt,fac[N],ifac[N],ans; long long pfx[N],sum;
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void init(CI n)
{
	RI i; for (fac[0]=i=1;i<=n;++i) fac[i]=1LL*fac[i-1]*i%mod;
	for (ifac[n]=quick_pow(fac[n]),i=n-1;~i;--i) ifac[i]=1LL*ifac[i+1]*(i+1)%mod;
}
inline int C(CI n,CI m)
{
	return 1LL*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i,j; for (scanf("%d%d",&n,&m),i=1;i<=n;++i)
	scanf("%d",&a[i]),pfx[i]=pfx[i-1]+a[i]; sum=pfx[n];
	if (sum%2==0)
	{
		for (j=0,i=1;i<n;++i)
		{
			while (pfx[i]-pfx[j]>sum/2LL) ++j;
			if (pfx[i]-pfx[j]==sum/2LL) ++cnt;
		}
	}
	for (init(max(m,cnt)),i=0;i<=min(m,cnt);++i)
	(ans+=1LL*C(cnt,i)*C(m,i)%mod*fac[i]%mod*quick_pow(1LL*(m-i)*(m-i-1)%mod,cnt-i)%mod*quick_pow(m-i,n-cnt*2)%mod)%=mod;
	return printf("%d",ans),0;
}

H. Hot Black Hot White

昨天不小心漏看了这道过的人300+的题了,其实比H,C都简单啊(触发:构造题精通

首先由于模\(3\)的性质可以转为求一个数每位上数字的和,因此\(\operatorname{concat}(x,y)\equiv(x+y)\mod 3\)

因此\(\operatorname{concat}(A_i, A_j) \times \operatorname{concat}(A_j, A_i) + A_i \times A_j \equiv (A_i+A_j)^2+A_i\times A_j \equiv A_i^2+A_j^2\mod 3\)

稍加讨论,我们发现\(A_i^2\bmod 3\)的值只可能是\(0/1\),一个naive的想法,令\(Z=0/2\),把所有\(A_i^2\bmod 3=0\)的数变白,把所有\(A_i^2\bmod 3=1\)的数变黑,即满足和不会反应的条件

那么这样不一定满足颜色的个数相等,因此我们讨论一下:

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int n,a[N],b[N],c[2],cnt;
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i; for (scanf("%d",&n),i=1;i<=n;++i)
	scanf("%d",&a[i]),++c[b[i]=1LL*a[i]*a[i]%3];
	if (c[0]>=c[1])
	{
		for (puts("2"),i=1;i<=n;++i) if (b[i]==1) putchar('1');
		else if (b[i]==0&&cnt<n/2) putchar('0'),++cnt; else putchar('1');
	} else
	{
		for (puts("0"),i=1;i<=n;++i) if (b[i]==0) putchar('0');
		else if (b[i]==1&&cnt<n/2) putchar('1'),++cnt; else putchar('0');
	}
	return 0;
}

F. Field Photography

首先由于移动的次数不限,并且最后要满足或起来是一个数,我们考虑令\(k=\operatorname{LSB}(W_j)\),其中\(\operatorname{LSB}(x)\)表示\(x\)的二进制下从低位到高位第一个\(1\)的位置

不难发现由于或的性质,我们每次操作的步数必须是\(2^k\)的倍数,考虑以下一种移动方案:

不难发现这样一定是最优的(每次移动的单位长度最短)并且满足题目要求

不难发现此时我们只关心区间端点对\(2^k\)取模后的结果,具体的:

因此问题变为区间修改+全局最值,结果我这个傻狗去写线段树,然后常数太大T了,后来一想发现直接差分就好了

由于\(\operatorname{LSB}(x)\)的范围是\(\log W_j\)级别的,总复杂度\(O(n\log n\log W_j)\)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<utility>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
using namespace std;
const int N=100005;
typedef pair <int,int> pi;
int n,l[N],r[N],q,x,ans[35],cnt,sum; pi rst[N<<2];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i,j; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d%d",&l[i],&r[i]);
	for (j=0;j<=30;++j)
	{
		int k=1<<j; for (cnt=0,i=1;i<=n;++i)
		if (r[i]-l[i]+1>=k) rst[++cnt]=mp(0,1),rst[++cnt]=mp(k,-1);
		else if (l[i]%k<=r[i]%k) rst[++cnt]=mp(l[i]%k,1),rst[++cnt]=mp(r[i]%k+1,-1);
		else rst[++cnt]=mp(l[i]%k,1),rst[++cnt]=mp(k,-1),rst[++cnt]=mp(0,1),rst[++cnt]=mp(r[i]%k+1,-1);
		for (sort(rst+1,rst+cnt+1),sum=0,i=1;i<=cnt;++i)
		sum+=rst[i].se,ans[j]=max(ans[j],sum);
	}
	for (scanf("%d",&q),i=1;i<=q;++i)
	for (scanf("%d",&x),j=0;j<=30;++j)
	if ((x>>j)&1) { printf("%d\n",ans[j]); break; }
	return 0;
}

标签:cnt,const,14,int,bmod,Preliminary,Mirror,include,define
来源: https://www.cnblogs.com/cjjsb/p/16686695.html