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
,其中r
与g
不可有序相邻。
先考虑只有rg
,r
和b
的情况,方案数为 $$\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\) 时刻能去到的价值):
考虑去掉这个绝对值符号:
由于 \(x-x'\) 和 \(-(x-x')\) 肯定一正一负,而负值一定小于正值,可以得出:
移一下项:
令 \(a-t-x-y,b=t+x-y\),所以 \((t,x,y)\) 可以由 \((a,b,y)\) 表示。
所以方程就变成了
这样,问题就转化为三维偏序了。
我们就可以愉快的暴力了(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;
}