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\) 对,然后再随意分配:
//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]\)

浙公网安备 33010602011771号