AtCoder Beginner Contest 266

A

给定一个长度为奇数的字符串,求其中间字符。

设字符串的长度为 \(n\),其中间字符即为 \(s[n/2]\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
string s;
signed main()
{
	cin>>s;
	cout<<s[s.size()/2];
	return 0;
}

B

给定一个整数 \(n\),求 \(n\bmod 998244353\)

直接 \(\bmod\) 会出现负数,所以模之后如果是负数需要 \(+\bmod\)

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
int n;
signed main()
{
	cin>>n;
	cout<<(mod+n%mod)%mod;
	return 0;
}

C

给定 \(4\) 个点,判断这四个点组成的四边形是否为凸四边形。

如果 \(\angle AOB<180^\circ\)\(A_xB_y-A_yB_x>0\),反之亦然。

可以以每一个点为 \(O\),看他和旁边两个点形成的角的度数是否小于 \(180^\circ\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int ax,ay,bx,by,cx,cy,dx,dy;
bool solve(int ax,int ay,int bx,int by,int cx,int cy,int dx,int dy)
{
	int z1,z2,z3,z4;
	z1=(bx-ax)*(dy-ay)-(dx-ax)*(by-ay);
	z2=(cx-bx)*(ay-by)-(ax-bx)*(cy-by);
	z3=(dx-cx)*(by-cy)-(bx-cx)*(dy-cy);
	z4=(ax-dx)*(cy-dy)-(cx-dx)*(ay-dy);
	return (z1>0)&&(z2>0)&&(z3>0)&&(z4>0);
}
int main()
{
	cin>>ax>>ay>>bx>>by>>cx>>cy>>dx>>dy;
	if(solve(ax,ay,bx,by,cx,cy,dx,dy))cout<<"Yes";
	else cout<<"No";
	return 0;
}

D

\(5\) 根数轴,在这些数轴上有一些点,点有点权,且点只在固定时间出现一次。现在你从 \(0\) 出发,每次最多移动一个点,一个数轴,求能取到的最大点权。

题意描述不太清楚,可以看原题。
考虑 dp,设 \(dp[i][0\sim4]\) 表示在 \(i\) 时刻在哪个数轴上的最大收益。
转移见代码。

点击查看代码
#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N=2e5+5;
int n,t[N],x[N],a[N],dp[N][5];
map<pair<int,int>,int>mp;
signed main()
{
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		cin>>t[i]>>x[i]>>a[i];
		mp[{t[i],x[i]}]=a[i];
	}
	int mx=t[n];
	for(int i=1;i<=mx;++i)
	{
		dp[i][0]=max(dp[i-1][0],dp[i-1][1])+mp[{i,0}];
		if(i>=1)dp[i][1]=max(dp[i-1][1],max(dp[i-1][0],dp[i-1][2]))+mp[{i,1}];
		if(i>=2)dp[i][2]=max(dp[i-1][2],max(dp[i-1][1],dp[i-1][3]))+mp[{i,2}];
		if(i>=3)dp[i][3]=max(dp[i-1][3],max(dp[i-1][2],dp[i-1][4]))+mp[{i,3}];
		if(i>=4)dp[i][4]=max(dp[i-1][4],dp[i-1][3])+mp[{i,4}];
	}
	cout<<max(dp[mx][0],max(dp[mx][1],max(dp[mx][2],max(dp[mx][3],dp[mx][4]))));
	return 0;
}

E

最多扔 \(n\) 次骰子,求最后一次扔到的数的期望最大值。

考虑 dp,设 \(dp[i]\) 表示扔 \(i\) 次骰子的期望最大值。
转移时枚举这次投到的数,若大于 \(dp[i-1]\),则继续投,若小于,则停止。方程见代码。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
double dp[105];
signed main()
{
	cin>>n;
	dp[1]=3.5;
	for(int i=2;i<=n;++i)
		for(int j=1;j<=6;++j)
			dp[i]+=max(j*1.0,dp[i-1])/6;
	printf("%.7f",dp[n]);
	return 0;
}

F

给定一颗基环树,求两点之间的路径上是否经过环。

可以先通过拓扑排序找出环打上标记,之后从环上的每一个点开始搜索,找到每一个点的“根”。询问的时候只要判断两个点的“根”先不相同即可。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,q,deg[N],cir[N],fa[N];
vector<int>g[N];
inline void dfs(int st,int u,int f)
{
	fa[u]=st;
	for(int i=0;i<g[u].size();++i)
	{
		int v=g[u][i];
		if(cir[v]||v==f)continue;
		dfs(st,v,u);
	}
}
signed main()
{
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		int u,v;cin>>u>>v;
		g[u].push_back(v);g[v].push_back(u);
		deg[u]++;deg[v]++;
	}
	queue<int>que;
	for(int i=1;i<=n;++i)
	{
		if(deg[i]==1)que.push(i);
		cir[i]=1;
	}
	while(!que.empty())
	{
		int u=que.front();que.pop();cir[u]=0;
		for(int i=0;i<g[u].size();++i)
		{
			int v=g[u][i];deg[v]--;
			if(deg[v]==1)que.push(v);
		}
	}
	for(int i=1;i<=n;++i)
		if(cir[i])dfs(i,i,i);
	cin>>q;
	while(q--)
	{
		int x,y;cin>>x>>y;
		if(fa[x]==fa[y])cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
	}
	return 0;
}

G

一个由 \(r\)r\(g\)g\(b\)b排列组成的字符串,求其中rg子串出现次数为 \(k\) 的方案数。

变形:\(k\)rg\(r-k\)r\(g-k\)g\(b\)b,其中rg不可有序相邻。

先考虑只有rgrb的情况,方案数为 $$\dfrac{[k+(r-k)+b]!}{k!(r-k)!b!}$$
考虑插入g,可插的空有 \(k+b+1\) 个。
方案数为 $$\dbinom{k+b+1+(g-k)-1}{g-k}$$
所以答案为 $$\dfrac{(r+b)!}{k!(r-k)!b!}\dbinom{b+g}{g-k}$$

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
const int N=3e6+5;
int r,g,b,k,fact[N],inv_fact[N];
int Qpow(int x,int p)
{
	int res=1;
	for(;p;p>>=1,(x*=x)%=mod)
		if(p&1)(res*=x)%=mod; 
	return res;
}
void init()
{
	fact[0]=1;
	for(int i=1;i<=3000000;++i)
		fact[i]=fact[i-1]*i,fact[i]%=mod;
	inv_fact[3000000]=Qpow(fact[3000000],mod-2);
	for(int i=2999999;i>=0;--i)
		inv_fact[i]=inv_fact[i+1]*(i+1)%mod;
}
signed main()
{
	cin>>r>>g>>b>>k;
	init();
	cout<<fact[r+b]*inv_fact[k]%mod*inv_fact[r-k]%mod*inv_fact[b]%mod*fact[g+b]%mod*inv_fact[g-k]%mod*inv_fact[b+k]%mod;
	return 0;
}

Ex

D 的加强版,题意不易描述,就不描述了。

暴力艹过去了。https://atcoder.jp/contests/abc266/submissions/34441877

考虑 dp,设 \(dp[x][y][t]\) 表示在 \(t\) 时间走到 \((x,y)\) 点能取到的最大价值。
不难得出方程(\(A(x,y,t)\) 表示在 \((x,y)\) 点在 \(t\) 时刻能去到的价值):

\[dp[x][y][t]=\max{\{dp[x'][y'][t']\mid y'\le y,|x-x'|+y-y'\le t-t'\}}+A(x,y,t) \]

考虑去掉这个绝对值符号:

\[|x-x'|+y-y'\le t-t' \]

由于 \(x-x'\)\(-(x-x')\) 肯定一正一负,而负值一定小于正值,可以得出:

\[x-x'+y-y'\le t-t'\ {\rm and}-(x-x')+y-y'\le t-t' \]

移一下项:

\[x-x'+y-y'\le t-t'\to t'-x'-y'\le t-x-y \]

\[-(x-x')+y-y'\le t-t'\to t'+x'-y'\le t+x-y \]

\(a-t-x-y,b=t+x-y\),所以 \((t,x,y)\) 可以由 \((a,b,y)\) 表示。
所以方程就变成了

\[dp[a][b][y]=\max{\{dp[a'][b'][y']\mid a'\le a,b'\le b,y'\le y\}}+A(x,y,t) \]

这样,问题就转化为三维偏序了。
我们就可以愉快的暴力了(bushi)

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define il inline
using namespace std;
const int N=1e5+5;
int n,cnt,dp[N],ans;
struct node{int t,a,b,y,val;}w[N];
il int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
il void write(int x)
{
	if(x<0){x=-x;putchar('-');}
	if(x>9)write(x/10);
	putchar(x%10+'0');
} 
bool cmp(node qx,node wx){return qx.t<wx.t;}
signed main()
{
	n=read();
	for(int i=1;i<=n;++i)
	{
		int t,x,y,a;cin>>t>>x>>y>>a;
		if(x+y>t)continue;
		w[++cnt].a=t-x-y;w[cnt].b=t+x-y;
		w[cnt].y=y;w[cnt].val=a;w[cnt].t=t;
	}
	sort(w+1,w+cnt+1,cmp);
	for(int i=1;i<=cnt;++i)
	{
		for(int j=i-1;j>=max(i-10000,1ll);--j)
			if(w[j].a<=w[i].a&&w[j].b<=w[i].b&&w[j].y<=w[i].y)
				dp[i]=max(dp[i],dp[j]);
		dp[i]+=w[i].val;
		ans=max(dp[i],ans);
	}
	cout<<ans;
	return 0;
}
posted @ 2022-08-28 11:25  lnwhl  阅读(70)  评论(4编辑  收藏  举报