AtCoder Grand Contest 021题解
A - Digit Sum 2:
尽量填9,否则第一位-1
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#define LL long long
using namespace std;
LL n,a[20],len=0;
int main()
{
scanf("%lld",&n);
while(n) a[++len]=n%10,n/=10;
bool flag=true;
for(int i=1;i<len;i++) if(a[i]!=9) {flag=false;break;}
if(flag) {printf("%lld",9*(len-1)+a[len]);return 0;}
printf("%lld",9*(len-1)+a[len]-1);
}
B - Holes:
先求凸包,显然凸包内的点是没有概率的。而凸包上的点的区域就是相邻做垂直平分线。
中间部分就假装交于一点(对概率没有影响),求出每个向量夹角即可。
code:
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
#define double long double
using namespace std;
const double pi=acos(-1);
struct poLL {LL x,y,num;}p[110],a[110];
double ans[110];
LL multi(poLL p1,poLL p2,poLL p0)
{
LL x1=p1.x-p0.x,y1=p1.y-p0.y;
LL x2=p2.x-p0.x,y2=p2.y-p0.y;
return x1*y2-x2*y1;
}
LL n,top=0,sta[110];
LL dis(poLL a,poLL b) {return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}
bool cmp(poLL a,poLL b)
{
LL t1=multi(b,a,p[1]);
return t1==0?dis(p[1],a)<dis(p[1],b):t1>0;
}
void solve()
{
for(LL i=2;i<=n;i++)
if((p[1].x==p[i].x)?(p[i].y<p[1].y):(p[i].x<p[1].x)) swap(p[1],p[i]);
sort(p+2,p+n+1,cmp);
sta[++top]=1;
for(LL i=2;i<=n;i++)
{
while(top>1&&multi(p[sta[top]],p[sta[top-1]],p[i])<0) top--;
sta[++top]=i;
}
}
double get(poLL p1,poLL p2,poLL p0)
{
LL x1=p1.x-p0.x,y1=p1.y-p0.y;
LL x2=p2.x-p0.x,y2=p2.y-p0.y;
return (double)(x1*x2+y1*y2)/(sqrt(x1*x1+y1*y1)*sqrt(x2*x2+y2*y2));
}
void calc()
{
if(top==0) for(LL i=1;i<=top;i++) ans[p[sta[i]].num]=0.5;
else
{
sta[0]=sta[top];sta[top+1]=sta[1];
for(LL i=1;i<=top;i++)
{
double tmp=get(p[sta[i-1]],p[sta[i+1]],p[sta[i]]);
double s=pi-acos(tmp);
ans[p[sta[i]].num]=s/(pi*2);
}
}
}
int main()
{
scanf("%lld",&n);
for(LL i=1;i<=n;i++) scanf("%lld %lld",&p[i].x,&p[i].y),p[i].num=i;
if(n==1) return puts("1.000000000000"),0;
solve();calc();
for(LL i=1;i<=n;i++) printf("%.9Lf\n",ans[i]);
}
C - Tiling:
尽量以2*2为一个单位,边界情况判一下。
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,a,b;
char s[1010][1010];
bool check1(int x,int y)
{
if(y==m||a==0) return false;
return s[x][y+1]=='.';
}
bool check2(int x,int y)
{
if(x==n||b==0) return false;
if(b==1)
{
if(((m%2)&&(y%2==0))||((m%2==0)&&(y%2)))
{
s[n-1][m]='^';s[n][m]='v';b--;
return false;
}
}
return s[x+1][y]=='.';
}
void dfs(int x,int y)
{
/*printf("x y:%d %d\n",x,y);
for(int i=1;i<=n;i++) printf("%s\n",s[i]+1);
printf("-----------------\n");*/
if(x==n+1) return;
if(s[x][y]=='.')
{
if(check2(x,y)) s[x][y]='^',s[x+1][y]='v',b--;
else if(check1(x,y)) s[x][y]='<',s[x][y+1]='>',a--;
}
if(y==m) dfs(x+1,1);
else dfs(x,y+1);
}
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(m%2)
{
for(int i=1;i<=n;i+=2)
{
if(i==n-1)
{
if(b%2==1&&check2(i,1)) s[i][1]='^',s[i+1][1]='v',b--;
}
if(check2(i,1)) s[i][1]='^',s[i+1][1]='v',b--;
}
//for(int j=1;j<=m;j++) if(check1(n,j)) s[n][j]='<',s[n][j+1]='>',a--;
}
dfs(1,1);
//for(int i=1;i<=n;i++) printf("%s\n",s[i]+1);
if(a!=0||b!=0) printf("NO\n");
else
{
printf("YES\n");
for(int i=1;i<=n;i++) printf("%s\n",s[i]+1);
}
}
D - Reversed LCS:
显然无修改就是最长回文子序列。
表示i~j,修改k次的最长回文子序列,转移显然。
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
const int inf=1<<28;
char s[310];
int n,f[310][310],g[310][310],K;
int main()
{
scanf("%s",s+1);n=strlen(s+1);
scanf("%d",&K);
memset(f,-63,sizeof(f));
for(int i=0;i<=K;i++) f[1][i]=1;
for(int i=2;i<=n;i++)
{
for(int j=1;j<i;j++)
for(int k=0;k<=K;k++) g[j][k]=f[j][k];
for(int j=0;j<=K;j++) g[i][j]=1;
for(int j=0;j<=K;j++)
{
int t1=0,t2=0;
for(int k=i-1;k>=1;k--)
{
t1=max(t1,f[k+1][j]);
if(j!=0) t2=max(t2,f[k+1][j-1]);
if(s[k]==s[i]) g[k][j]=max(g[k][j],t1+2);
else if(j!=0) g[k][j]=max(g[k][j],t2+2);
}
}
for(int j=1;j<=i;j++) for(int k=1;k<=K;k++) g[j][k]=max(g[j][k],g[j][k-1]);
for(int j=i-1;j>=1;j--) for(int k=0;k<=K;k++) g[j][k]=max(g[j][k],g[j+1][k]);
for(int j=1;j<=i;j++) for(int k=0;k<=K;k++) f[j][k]=max(f[j][k],g[j][k]);
}
int ans=0;
for(int i=1;i<=n;i++) for(int j=0;j<=K;j++) ans=max(ans,f[i][j]);
printf("%d",ans);
}
E - Ball Eat Chameleons:
题解
记住这个类似卡特兰数的算法。(总方案-到对称点方案)
code:
#include<cstdio>
#define LL long long
const LL mod=998244353;
LL fac[500010],inv[500010],N,K,ans=0;
void pre()
{
fac[0]=fac[1]=inv[0]=inv[1]=1;
for(LL i=2;i<=500000;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
for(LL i=2;i<=500000;i++) fac[i]=fac[i-1]*i%mod,inv[i]=inv[i-1]*inv[i]%mod;
}
LL C(LL m,LL n) {return fac[m]*inv[m-n]%mod*inv[n]%mod;}
int main()
{
pre();
scanf("%lld %lld",&N,&K);
if(N>K) return puts("0"),0;
for(int i=N;i<=K;i++) (ans+=C(K-1,i-1))%=mod;
printf("%lld",ans);
}
F - Contest with Drinks Hard:
留坑