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:

显然无修改就是最长回文子序列。
f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示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:

留坑

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值