# 【AtCoder】AtCoder Grand Contest 039 解题报告

### $A$：Connection and Disconnection（点此看题面）

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100
using namespace std;
string s,p;int n,k;
I bool Check() {for(RI i=1;i^n;++i) if(s[i]^s[i-1]) return false;return true;}//检查是否所有字符相同
int main()
{
RI i;long long t1=0,t2=0;if(cin>>s>>k,n=s.length(),Check()) return printf("%lld",(1LL*n*k)>>1),0;//特判所有字符相同
for(p=s,i=1;i^n;++i) s[i]==s[i-1]&&(s[i]=0,++t1);t1*=k,s[0]==s[n-1]&&(t1+=k-1);//正着求答案
for(s=p,i=n-2;~i;--i) s[i]==s[i+1]&&(s[i]=0,++t2);t2*=k,s[0]==s[n-1]&&(t2+=k-1);//倒着求答案
return printf("%lld",min(t1,t2)),0;//输出答案
}


### $B$：Graph Partition（点此看题面）

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200
using namespace std;
int n,p[N+5],q[N+5],a[N+5][N+5];
I int BFS(CI x)//BFS求答案
{
for(RI i=1;i<=n;++i) p[i]=0;//清空
RI i,k,H=1,T=1;p[q[1]=x]=1;W(H<=T) for(k=q[H++],i=1;i<=n;++i)
if(a[k][i]) {if(p[i]&&p[i]^(p[k]-1)&&p[i]^(p[k]+1)) return -1;!p[i]&&(p[q[++T]=i]=p[k]+1);}//若矛盾返回-1，否则赋值并加入队列
return p[q[T]];//返回答案
}
int main()
{
RI i,j,t,ans=-1;string s;for(scanf("%d",&n),i=1;i<=n;++i)
for(cin>>s,j=1;j<=n;++j) s[j-1]&1&&(a[i][j]=1);
for(i=1;i<=n;++i) ans<(t=BFS(i))&&(ans=t);return printf("%d",ans),0;//枚举起点输出答案
}


### $C$：Division by Two with Something（点此看题面）

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200000
#define X 998244353
#define Inc(x,y) ((x+=(y))>=X&&(x-=X))
using namespace std;
int n;int a[N+5],b[N+5],f[N+5],g[N+5];
int main()
{
RI i,j,p,k=0,t=0,cnt=0;string s;
for(scanf("%d",&n),cin>>s,i=1;i<=n;++i) a[i]=s[i-1]&1;//读入
for(i=1;i<=n;++i) if(!(n%i)&&(n/i)&1)//枚举一个符合条件的i
{
for(f[++k]=i,j=1;j<=i;++j) g[k]=(g[k]<<1|a[j])%X;++g[k];//计算合法数的个数上界，只需判断是否能够达到上界
for(j=1;j<=i;++j) b[j]=a[j];
for(j=i+1;j<=n;++j) if(b[j]=b[j-i]^1,a[j]^b[j]) {a[j]<b[j]&&--g[k];break;}//若超出范围，则个数无法达到上界，减1
}
for(i=1;i<=k;++i) for(j=i+1;j<=k;++j) !(f[j]%f[i])&&Inc(g[j],X-g[i]);//容斥
for(i=1;i<=k;++i) t=(2LL*f[i]*g[i]+t)%X,Inc(cnt,g[i]);//统计答案
return printf("%d",t),0;//输出答案
}


### $D$：Incenters（点此看题面）

$\because CC'$平分$\ang ACB,\therefore\ang ACC'=\ang BCC',\therefore$$AC'=$$BC',\therefore C'$是弧$AB$的中点$.$

$\because B'$是弧$AC$的中点$,\therefore B'D⊥AC,\therefore \ang CEN=90$$.$

$\because A'$是弧$BC$的中点$,B'$是弧$AC$的中点$,C'$是弧$AB$的中点$,\therefore$$AC'=\frac12$$AB,$$B'C=\frac12$$AC,$$A'C=\frac 12$$BC,\therefore$$AC'+$$B'C+$$A'C$的度数为$180$$.$

$\because B'D$是直径$,\therefore$$B'C+$$A'C+$$A'D$的度数为$180$$,\therefore$$AC'=$$A'D,\therefore\ang ACC'=\ang A'B'D.$

$\because CC'$平分$\ang ACB,\therefore \ang BCC'=\ang ACC',\therefore\ang BCC'=\ang A'B'D.$

$\because\ang CKM=\ang B'KN,\therefore\ang CMK=\ang B'NK.$

$\therefore \ang CKM=\ang CEN=90$$,\therefore CC'⊥A'B'.$

$AB$优弧上有$x$个点，劣弧上有$y$个点，那么$C'$的坐标期望就是$AB$劣弧中点坐标乘$\frac x{x+y}$$AB$优弧中点坐标乘$\frac y{x+y}$，其中显然$x+y=n-2$

$AB$作为红色三角形一边的概率是$\frac 1{C_n^2}=\frac 2{n(n-1)}$，因此将所有的$A,B$求出的坐标期望求和并乘上$\frac 2{n(n-1)}$，就是最后紫色三角形重心的坐标期望。

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 3000
#define DB double
using namespace std;
int n,l,a[N+5];const DB pi=acos(-1);
struct Point
{
DB x,y;I Point() {x=y=0;}I Point(Con DB& a):x(cos(2*pi*a/l)),y(sin(2*pi*a/l)){}//根据角度算坐标
I Point(Con DB& a,Con DB& b):x(a),y(b){}
I Point operator + (Con Point& t) Con {return Point(x+t.x,y+t.y);}
I Point operator * (Con DB& t) Con {return Point(x*t,y*t);}
}ans;
int main()
{
RI i,j;for(scanf("%d%d",&n,&l),i=1;i<=n;++i) scanf("%d",a+i);//读入角度
for(sort(a+1,a+n+1),i=1;i<=n;++i) for(j=i+1;j<=n;++j)//枚举两个点
ans=ans+Point((a[i]+a[j])/2.0)*(1.0*(n-2-(j-i-1)*2)/(n-2));//统计
return ans=ans*(6.0/n/(n-1)),printf("%.10lf %.10lf",ans.x,ans.y),0;//计算并输出答案
}


### $E$：Pairing Points（点此看题面）

• $[l,mid-1],[mid+1,r]$中的点都还未连边，且只会跟$[l,mid-1],[mid+1,r]$中的点连边。
• $mid$已和$[l,r]$外的一点连边。

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 20
#define LL long long
using namespace std;
int n,a[2*N+5][2*N+5];LL f[2*N+5][2*N+5][2*N+5];
I LL DP(CI l,CI r,CI mid)//处理某一局面
{
if(~f[l][r][mid]) return f[l][r][mid];if(l==r) return 1;if(l==mid||r==mid) return 0;//判边界
RI i,j,p,q;LL t=0;for(i=l;i^mid;++i) for(j=r;j^mid;--j) if(a[i][j])//枚举最靠外的边
for(p=i;p^mid;++p) for(q=j;q^mid;--q) t+=DP(l,p,i)*DP(p+1,q-1,mid)*DP(q,r,j);//枚举两个分界点，递归求答案
return f[l][r][mid]=t;//记忆化，返回答案
}
int main()
{
RI i,j;string s;memset(f,-1,sizeof(f));
for(scanf("%d",&n),i=1;i<=2*n;++i) for(cin>>s,j=1;j<=2*n;++j) a[i][j]=s[j-1]&1;//读入
LL t=0;for(i=2;i<=2*n;++i) a[1][i]&&(t+=DP(2,2*n,i));return printf("%lld",t),0;//枚举与1相对的点，统计答案并输出
}


### $F$：Min Product Sum（占坑待填）

$F$题显然不可做，看题解看了半个小时也没看懂。

posted @ 2019-11-11 15:57  TheLostWeak  阅读(163)  评论(0编辑  收藏