【Atcoder】AGC021 B-F简要题解

本文详细介绍了Atcoder AGC021竞赛中的B至F题,包括B.Holes的凸包概率计算,C.Tiling的特殊情况处理,D.Reversed LCS的动态规划解法,E.Ball Eat Chameleons的分类讨论和路径计数,以及F.Trinity的矩阵染色问题。每道题目均提供了思路和部分代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一场9h才做完的AGC,
我太菜了,哇的一声哭出来 (。﹏。)


*B.Holes

若所有点贡献则两个端点概率各为 0.5 0.5 0.5,其余点概率为 0 0 0

注意到 R = 1 0 1 0 1 0 10 R=10^{10^{10^{10}}} R=10101010实在太大了——求所有点的凸包,可以只计算凸包外的点到每个点的概率(凸包内的点可以忽略不计)。
凸包上每个点的概率即 π − θ i 2 π ( θ i \dfrac{\pi-\theta_i}{2\pi}(\theta_i 2ππθi(θi是点 i i i内夹角)

还有一种 O ( n 2 log ⁡ n ) O(n^2\log n) O(n2logn)的很好写的算法,戳这里


*C.Tiling

划分成 4 × 4 4\times 4 4×4的小方格,若 n , m n,m n,m为奇,单独用 1 × 2 , 2 × 1 1\times 2,2\times 1 1×2,2×1去填补最后一行/列。
注意特判右下角 3 × 3 3\times 3 3×3的方格(3同3异换成2同2异):
<>^
^*v
v<>

code from yfzcsc

#include<bits/stdc++.h>
using namespace std;
char s[1010][1010];
int n,m,a,b;
int main(){
    scanf("%d%d%d%d",&n,&m,&a,&b);
    for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)s[i][j]='.';
    if(n&1)for(int i=1;i<m&&a;i+=2)s[n][i]='<',s[n][i+1]='>',a--;
    if(m&1)for(int i=1;i<n&&b;i+=2)s[i][m]='^',s[i+1][m]='v',b--;
    for(int i=1;i<n;i+=2)
        for(int j=1;j<m;j+=2){
            if(a>=2){
                a-=2;
                s[i][j]='<',s[i][j+1]='>';
                s[i+1][j]='<',s[i+1][j+1]='>';
            } else if(b>=2){
                b-=2;
                s[i][j]='^',s[i][j+1]='^';
                s[i+1][j]='v',s[i+1][j+1]='v';
            } else if(a&&b&&i==n-2&&j==m-2){
                a--,b--;
                s[i][j]='<',s[i][j+1]='>',s[i][j+2]='^';
                s[i+1][j]='^',s[i+1][j+2]='v';
                s[i+2][j]='v',s[i+2][j+1]='<',s[i+2][j+2]='>';
            } else if(a){
                a--;
                s[i][j]='<',s[i][j+1]='>';
            } else if(b){
                b--;
                s[i][j]='^',s[i+1][j]='v';
            }
        }
    if(a||b)return puts("NO"),0;
    puts("YES");
    for(int i=1;i<=n;++i)puts(s[i]+1);
}

D.Reversed LCS

dp不解释


*E.Ball Eat Chameleons

zz了。想了好久。

一只变色龙最终变成红色的方案有两种:

  • c n t R = c n t B cnt_R=cnt_B cntR=cntB,且以 B B B结尾
  • c n t R &gt; c n t B cnt_R&gt;cnt_B cntR>cntB

考虑看成求解二维平面上 ( 0 , 0 ) → ( R , B ) (0,0)\to (R,B) (0,0)(R,B)的合法路径数,分类讨论如下:

  • R = B R=B R=B,则最后一个球必然是蓝色的( ( R , B − 1 ) → ( R , B ) (R,B-1)\to (R,B) (R,B1)(R,B)),贪心确定合法:取出 n n n对有序的 R B RB RB,剩下的全部分给其中一对。可知答案路径不经过 y − x ≥ R − n + 1 y-x\geq R-n+1 yxRn+1(即 max ⁡ ( y − x ) ≤ R − n \max(y-x)\leq R-n max(yx)Rn, max ⁡ ( y − x ) \max(y-x) max(yx)表示剩下的不能与左边的 R R R配对的 B B B的个数)
  • R ≠ B R\neq B R̸=B,贪心确定合法:取 n − ( R − B ) n-(R-B) n(RB)对有序的 R B RB RB R − B R-B RB R R R,剩下的全部分给其中一个 R R R。同样剩下的蓝球要 ≤ B − ( n − ( R − B ) ) = R − n \leq B-(n-(R-B))=R-n B(n(RB))=Rn,故答案路径不经过 y − x ≥ R − n + 1 y-x\geq R-n+1 yxRn+1

卡特兰数计算:

R = B R=B R=B的答案: ( R + B − 1 R ) − ( R + B − 1 2 R − n + 1 ) \dbinom{R+B-1}{R}-\dbinom{R+B-1}{2R-n+1} (RR+B1)(2Rn+1R+B1)

R ≠ B R\neq B R̸=B的答案: ( R + B R ) − ( R + B 2 R − n + 1 ) \dbinom{R+B}{R}-\dbinom{R+B}{2R-n+1} (RR+B)(2Rn+1R+B)


*F.Trinity

MDyfzcsc的题解真心看不懂,还是wxh010910的题解良心!

d p [ i ] [ j ] dp[i][j] dp[i][j]为强制每行都有格子染黑的 i i i j j j列矩阵的方案数。

每次列数 j + 1 j+1 j+1拓展, d p [ i ] [ j ] → d p [ i + k ] [ j + 1 ] dp[i][j]\to dp[i+k][j+1] dp[i][j]dp[i+k][j+1](枚举 k k k表示新出现了 k k k行,这些行的第一个被染黑的格子在 j + 1 j+1 j+1列出现),分类讨论:

  • k = 0 k=0 k=0,在第 j + 1 j+1 j+1列随意选0,1,2个端点,方案数 1 + i + ( i 2 ) 1+i+\binom{i}{2} 1+i+(2i)
  • k &gt; 0 k&gt;0 k>0,放置完 k k k行后,可以在这些行之上选一个属于原来 i i i行中的行 p p p ( p , j + 1 ) (p,j+1) (p,j+1)染色,使得 B j + 1 = p B_{j+1}=p Bj+1=p,也可以在这些行之下选一个属于原来 i i i行中的行 q q q ( q , j + 1 ) (q,j+1) (q,j+1)染色,使得 C j + 1 = q C_{j+1}=q Cj+1=q,那么可以多加 2 2 2行分别代表 B j + 1 , C j + 1 B_{j+1},C_{j+1} Bj+1,Cj+1,同时给新增的 k k k行也增加 2 2 2行表示 k k k行中的最小/大行,方案数即 ( i + k + 2 k + 2 ) \binom{i+k+2}{k+2} (k+2i+k+2)
    正确性:每一种组合都对应着 k k k新增的两行是否选中的全局对应 B j + 1 , C j + 1 B_{j+1},C_{j+1} Bj+1,Cj+1的两行的某种方案。稍微有点感性…

a n s = ∑ i = 0 n ( n i ) d p [ i ] [ m ] ans=\sum \limits_{i=0}^n \binom{n}{i}dp[i][m] ans=i=0n(in)dp[i][m]

合并是个卷积,复杂度 O ( n m log ⁡ n ) O(nm\log n) O(nmlogn)

#include<bits/stdc++.h>
#define pb push_back
#define gc getchar 
using namespace std;
const int N=5e4+10,mod=998244353,g=3;
typedef long long ll;
typedef double db;

int n,m,ans,f[N],h[N],t[N],frc[N],nv[N],ivg;

char cp;
template<class T>inline void rd(T &x)
{
	cp=gc();x=0;int f=0;
	for(;!isdigit(cp);cp=gc()) if(cp=='-') f=1;
	for(;isdigit(cp);cp=gc()) x=x*10+(cp^48);
	if(f) x=-x;
}

inline int fp(int x,int y)
{
	int re=1;
	for(;y;y>>=1,x=(ll)x*x%mod)
	  if(y&1) re=(ll)re*x%mod;
	return re;
}

inline int ad(int x,int y){x+=y;return x>=mod?x-mod:x;}
inline int dc(int x,int y){x-=y;return x<0?x+mod:x;} 
inline int C(int n,int m)
{
	if(m>n) return 0;
	return (ll)frc[n]*nv[m]%mod*(ll)nv[n-m]%mod;
}

namespace poly{
   int rv[N],L,len;
   
   inline void ntt(int *e,int pr)
   {
   	   int i,j,k,ix,iy,pd,ori,G=pr?g:ivg;
   	   for(i=1;i<len;++i) if(i<rv[i]) swap(e[i],e[rv[i]]);
   	   for(i=1;i<len;i<<=1){
   	      ori=fp(G,(mod-1)/(i<<1));
   	      for(j=0;j<len;j+=(i<<1)){
   	      	for(pd=1,k=0;k<i;++k,pd=(ll)pd*ori%mod){
   	      		ix=e[j+k];iy=(ll)pd*e[j+i+k]%mod;
   	      		e[j+k]=ad(ix,iy);e[i+j+k]=dc(ix,iy);
			}
		  }
	   }
	   if(pr) return;
	   G=fp(len,mod-2);
	   for(i=0;i<len;++i) e[i]=(ll)e[i]*G%mod;
   }
   
   void mul(int *f,int *g,int n,int m)
   {
   	   int i;
   	   for(L=0,len=1;len<=n+m;len<<=1) L++;
	   for(i=1;i<len;++i) rv[i]=(rv[i>>1]>>1)|((i&1)<<(L-1));
	   for(i=n+1;i<len;++i) f[i]=0;
   	   for(i=m+1;i<len;++i) g[i]=0;
   	   ntt(f,1);ntt(g,1);
   	   for(i=0;i<len;++i) f[i]=(ll)f[i]*g[i]%mod;
	   ntt(f,0); 
   }
}
using namespace poly;

int main(){
	int i,j,x,y;ivg=fp(g,mod-2);
	rd(n);rd(m);
	f[0]=frc[0]=nv[0]=frc[1]=nv[1]=1;
    for(i=2;i<n+3;++i)
	  frc[i]=(ll)frc[i-1]*i%mod,
	  nv[i]=(ll)(mod-mod/i)*nv[mod%i]%mod;
	for(i=2;i<n+3;++i) nv[i]=(ll)nv[i-1]*nv[i]%mod;
	for(i=1;i<=n;++i) h[i]=nv[i+2];
	for(L=0,len=1;len<=(n<<1);len<<=1) L++;
	for(i=1;i<len;++i) rv[i]=((rv[i>>1]>>1)|((i&1)<<(L-1)));
	ntt(h,1);
	for(j=1;j<=m;++j){
		for(i=0;i<=n;++i) t[i]=(ll)nv[i]*f[i]%mod;
		for(i=n+1;i<len;++i) t[i]=0;
		ntt(t,1);
		for(i=0;i<len;++i) t[i]=(ll)h[i]*t[i]%mod;
		ntt(t,0);
		for(i=0;i<=n;++i)
		 f[i]=ad((ll)(1+C(i+1,2))*f[i]%mod,(ll)t[i]*frc[i+2]%mod);
	}
	for(i=0;i<=n;++i) ans=ad(ans,(ll)C(n,i)*f[i]%mod);
	printf("%d",ans);
	return 0;
}

AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道题的简要题解: A - Dodecagon 题目描述:已知一个正十二边形的边长,求它的面积。 解题思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 题目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解题思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 题目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解题思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 题目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解题思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值