AtCoder Regular Contest 102

Contest Link 是思维场呢。

D - All Your Paths are Different Lengths

构造一张点数不超过 \(20\) 、边数不超过 \(60\) 的有向图,边权不超过 \(1e6\) ,使得 \(1\to N\) 的路径恰好 \(L\) 条,且路径长度为 \(0\sim L-1\) .


由于 \(2^{20}=1048576\) ,所以很自然的想法是二进制拆分。

对于最大的 \(n\) 使得 \(2^{n-1}\leq L\) ,我们可以用 \(n\) 个点构造出 \(1\to n\) 路径长度为 \(0\sim 2^{n-1}-1\) 的一张有向图:考虑点 \(i=1\sim n-1\)

  • \(i\)\(i+1\) 连两条边,一条边权为 \(0\) ,一条边权为 \(2^{i-1}\) .

按照一种类似数位DP的思想,现在要处理的就是大于 \(2^{n-1}\sim L\) 的部分。

从高到低,按位考虑 \(L\) 所有二进制下为 \(1\) 的位,设之前已经处理完的数位(就是之前的 \(2^{n-1}\) 加上已经搞完的为 \(1\) 的位所代表的数)和为 \(pre\) ,那么从 \(i\)\(n\) 连一条权值为 \(pre\) 的边,就表示出了 \(pre+0\sim pre+2^{i-1}-1\) ,然后累加 \(pre\) ,直到表示范围拓展到 \(L-1\) 结束。

可以看看代码理解。

//Author: RingweEH
int L,n,m;

int main()
{
	L=read();
	for ( n=1; (1<<n)<=L; n++ );
	for ( int i=0; i<n; i++ ) if ( L&(1<<i) ) m++;
	printf( "%d %d\n",n,m-1+2*(n-1) );
	for ( int i=1; i<n; i++ ) printf( "%d %d %d\n%d %d %d\n",i,i+1,0,i,i+1,1<<(i-1) );
	for ( int pre=(1<<n-1),i=n; i--; ) 
		if ( L&(1<<i-1) ) printf( "%d %d %d\n",i,n,pre ),pre+=(1<<i-1);

  	return 0;
}

E - Stop. Otherwise...

\(n\) 个骰子,每个标了 \(1\sim K\) ,对于 \(i=2\sim 2K\) ,求

  • 不存在任意两个骰子的点数和为 \(i\) 的情况数(骰子无标号)

考虑容斥。设组成和为 \(x\) 的方案数为 \(cnt\)\(f[i]\) 表示至少有 \(i\) 对和为 \(x\) 的方案数,答案就是 \(\sum\limits_{i=1}^{cnt}(-1)^if[i]\) 。计算 \(f[i]\) 就是强制选择 \(i\) 对,然后再随意分配:

\[f[i]=\binom {cnt}i\binom{n-2i+K-1}{K-1} \]

//Author: RingweEH
void Init()
{
	fac[0]=infac[0]=1;
	for ( int i=1; i<=n+k; i++ ) fac[i]=1ll*fac[i-1]*i%Mod;
	infac[n+k]=power(fac[n+k]);
	for ( int i=n+k-1; i>=1; i-- ) infac[i]=1ll*infac[i+1]*(i+1)%Mod;
	for ( int i=1; i<=k; i++ ) s[i+1]++,s[i+k+1]--;
	for ( int i=1; i<=k+k; i++ ) s[i]+=s[i-1];
}

int main()
{
	k=read(); n=read(); Init();
	for ( int i=2; i<=k+k; i++ )
	{
		int cnt=(s[i]+1)/2,ans=0;
		for ( int j=0,nw=1; j<=cnt && j+j<=n; j++,nw=Mod-nw )
			bmod( ans,1ll*nw*C(cnt,j)%Mod*C(n-2*j+k-1,k-1)%Mod);
		printf( "%d\n",ans );
	}

	return 0;
}

F - Revenge of BBuBBBlesort!

给定一个 \(1\sim n\) 的排列 \(p\) ,问是否能通过以下操作变成 \(p[i]=i\)

  • 选择 \(p[i-1],p[i],p[i+1]\) 满足 \(p[i-1]>p[i]>p[i+1]\) ,交换 \(p[i-1],p[i+1]\)

一开始脑子一抽写了一发左边搞一遍右边搞一遍的垃圾算法上去……然后居然过了 \(\dfrac 23\) /jk

正解 是这样的:

\(a[i]=[b[i]=i]\) ,定义一个区间合法为: 01 交错,且两端为 0

有结论:

  • 一个位置(为中心)动了一次,就不会动第二次。(考虑大小关系)

  • 如果 \(a\) 中有三个连续的 \(0\) ,没有方案。(上一个的推论)

先最大化每个位置所在合法序列长度,如果所有合法序列同时满足以下条件,存在方案。对于一个 \([l,r]\)

  • 元素值域 \([l,r]\)

  • 目标在左边的位置,\(\forall i<j,a[i]<a[j]\)

  • 目标在右边的位置,\(\forall i<j,a[i]<a[j]\)

posted @ 2021-02-19 18:37  MontesquieuE  阅读(70)  评论(0)    收藏  举报