一场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 > c n t B cnt_R>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,B−1)→(R,B)),贪心确定合法:取出 n n n对有序的 R B RB RB,剩下的全部分给其中一对。可知答案路径不经过 y − x ≥ R − n + 1 y-x\geq R-n+1 y−x≥R−n+1(即 max ( y − x ) ≤ R − n \max(y-x)\leq R-n max(y−x)≤R−n, max ( y − x ) \max(y-x) max(y−x)表示剩下的不能与左边的 R R R配对的 B B B的个数)
- R ≠ B R\neq B R̸=B,贪心确定合法:取 n − ( R − B ) n-(R-B) n−(R−B)对有序的 R B RB RB, R − B R-B R−B个 R R R,剩下的全部分给其中一个 R R R。同样剩下的蓝球要 ≤ B − ( n − ( R − B ) ) = R − n \leq B-(n-(R-B))=R-n ≤B−(n−(R−B))=R−n,故答案路径不经过 y − x ≥ R − n + 1 y-x\geq R-n+1 y−x≥R−n+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+B−1)−(2R−n+1R+B−1)
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)−(2R−n+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
>
0
k>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=0∑n(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;
}