G题 Icon Design
思路:等比例输出图形即可。
#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
scanf("%d",&n);
for(int i=1;i<=13*n+19;i++) cout<<'*';
cout<<endl;
for(int i=1;i<=n;i++){
cout<<'*';
for(int j=1;j<=13*n+17;j++) cout<<'.';
cout<<'*';
cout<<endl;
}
for(int i=1;i<=2*n+3;i++){
cout<<'*';
for(int j=1;j<=n+1;j++) cout<<'.';
cout<<'@';
for(int j=2;j<=2*n+2;j++){
if(j==i) cout<<'@';
else cout<<'.';
}
cout<<'@';
for(int j=1;j<=n+1;j++) cout<<'.';
cout<<'@';
for(int j=1;j<=2*n+2;j++){
if(i==1||i==n+2) cout<<'@';
else cout<<'.';
}
for(int j=1;j<=n+1;j++) cout<<'.';
cout<<'@';
for(int j=1;j<=2*n+2;j++){
if(i==2*n+3) cout<<'@';
else cout<<'.';
}
for(int j=1;j<=n+1;j++) cout<<'.';
if(i<=n+2||i==2*n+3) cout<<'@';
else cout<<'.';
for(int j=1;j<=2*n+1;j++){
if(i==1||i==n+2||i==2*n+3) cout<<'@';
else cout<<'.';
}
if(i==1||i>=n+2) cout<<'@';
else cout<<'.';
for(int j=1;j<=n+1;j++) cout<<'.';
cout<<'*';
cout<<endl;
}
for(int i=1;i<=n;i++){
cout<<'*';
for(int j=1;j<=13*n+17;j++) cout<<'.';
cout<<'*';
cout<<endl;
}
for(int i=1;i<=13*n+19;i++) cout<<'*';
}
J题 Number Game
思路:列出abc的变化公式然后找出规律,只有符合公式的情况才能够将c变化成x,其他情况都不行。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t,a,b,c,x;
int main(){
scanf("%lld",&t);
while(t--){
scanf("%lld%lld%lld%lld",&a,&b,&c,&x);
if(a-2*b==0) {
if(c==x||b-c==x) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
else {
ll d=(x%abs(a-2*b)+abs(a-2*b))%abs(a-2*b);
c=(c%abs(a-2*b)+abs(a-2*b))%abs(a-2*b);
ll y=((b-c)%abs(a-2*b)+abs(a-2*b))%abs(a-2*b);
if(c==d||y==d) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
}
M题 Z-Game On the Grid
题意:爱丽丝和鲍勃正在玩一个n×m网格的游戏,其中每个单元格都有“A”、“B”或“.”写在上面。他们轮流在格子上移动棋子,爱丽丝先移动。最初,该棋子位于单元格(1,1)上。在每个玩家的回合中,他或她可以将棋子向右移动一格或向下移动一格。也就是说,如果该棋子在回合前位于单元格(x,y)上,玩家可以将其移动到(x+1,y)或(x,y+1),只要它不超出网格。在任何时候,如果棋子在有“A”的单元格上,爱丽丝赢,游戏结束。如果棋子在有“B”的单元格上,鲍勃获胜,游戏结束。如果棋子到达单元格(n,m)而游戏没有结束,那么它是一个平局。问Alice是否有必胜策略。
思路:博弈DP,博弈状态就是fij,代表走到这先手是否总有一种方法让他赢,平或输,思考第一种让他赢得方式,边界就是走到A的地方就必定有,走到B的地方就必定没有,走到(n,m)也必定没有,其他时候如果Alice走,向右或向下有只要有一个地方有必赢方案,这里的状态也为有必赢方案,若Bob走,只有当向下和向右走都有必赢方案是此状态才有必赢方案。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=510;
int f[N][N];
char s[N][N];
int n,m;
int dfs1(int x,int y){
if(f[x][y]!=-1)return f[x][y];
if(s[x][y]=='B')return f[x][y]=0;
if(s[x][y]=='A')return f[x][y]=1;
if(x==n&&y==m)return f[x][y]=0;
if((x+y)%2==0){
if(x==n)return f[x][y]=dfs1(x,y+1);
else if(y==m)return f[x][y]=dfs1(x+1,y);
else return f[x][y]=(dfs1(x+1,y)||dfs1(x,y+1));
}
else{
if(x==n)return f[x][y]=dfs1(x,y+1);
else if(y==m)return f[x][y]=dfs1(x+1,y);
else return f[x][y]=(dfs1(x+1,y)&&dfs1(x,y+1));
}
}
int dfs2(int x,int y){
if(f[x][y]!=-1)return f[x][y];
if(s[x][y]=='B')return f[x][y]=0;
if(s[x][y]=='A')return f[x][y]=0;
if(x==n&&y==m)return f[x][y]=1;
if((x+y)%2==0){
if(x==n)return f[x][y]=dfs2(x,y+1);
else if(y==m)return f[x][y]=dfs2(x+1,y);
else return f[x][y]=(dfs2(x+1,y)||dfs2(x,y+1));
}
else{
if(x==n)return f[x][y]=dfs2(x,y+1);
else if(y==m)return f[x][y]=dfs2(x+1,y);
else return f[x][y]=(dfs2(x+1,y)&&dfs2(x,y+1));
}
}
int dfs3(int x,int y){
if(f[x][y]!=-1)return f[x][y];
if(s[x][y]=='B')return f[x][y]=1;
if(s[x][y]=='A')return f[x][y]=0;
if(x==n&&y==m)return f[x][y]=0;
if((x+y)%2==0){
if(x==n)return f[x][y]=dfs3(x,y+1);
else if(y==m)return f[x][y]=dfs3(x+1,y);
else return f[x][y]=(dfs3(x+1,y)|dfs3(x,y+1));
}
else{
if(x==n)return f[x][y]=dfs3(x,y+1);
else if(y==m)return f[x][y]=dfs3(x+1,y);
else return f[x][y]=(dfs3(x+1,y)&dfs3(x,y+1));
}
}
int main(){
int T;
cin>>T;
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
memset(f,-1,sizeof(f));
dfs1(1,1);
if(f[1][1]==1)cout<<"yes"<<' ';
else cout<<"no"<<' ';
memset(f,-1,sizeof(f));
dfs2(1,1);
if(f[1][1]==1)cout<<"yes"<<' ';
else cout<<"no"<<' ';
memset(f,-1,sizeof(f));
dfs3(1,1);
if(f[1][1]==1)cout<<"yes"<<' ';
else cout<<"no"<<' ';
puts("");
}
return 0;
}
B题 Eezie and Pie
思路:对于一个节点能够往其他点配送当且仅当那个节点的d[i]>=两个节点的距离,并且配送的节点深度>=当前节点。因此我们考虑每一个节点,有多少个节点能够配送到该节点。也就是从节点i向根方向找出一个长度为d[i]的链,这个链上的所有节点都可以往i节点送一个派。也就是树链上所有节点+1,最后统计所有节点上的值即可。首先暴力一点想到用树剖。对于区间操作,可以变成差分操作。起点位置+1,终点位置-1即可。最后用一遍dfs统计答案。对于找到终点位置,用倍增思想找<=depth[i] - d[i]的节点即可,注意边界。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
const int N = 2e6 + 10 , M = 4e6 + 10;
int h[N], e[M], ne[M], idx;
int id[N], cnt, out[N];
int dep[N], sz[N], top[N], fa[N], son[N];
int n, m;
int d[N];
int fat[N][30];
int f[N],w[N];
void add(int a, int b) // 添加一条边a->b
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void dfs1(int u, int father)
{
dep[u] = dep[father] + 1;
sz[u] = 1;
fa[u] = father;
for(int k = 1 ; k <= 25 ; k ++ )
fat[u][k] = fat[fat[u][k - 1]][k - 1];
for(int i = h[u]; ~i ; i = ne[i])
{
int j = e[i];
if(j == father) continue;
fat[j][0] = u;
dfs1(j, u);
sz[u] += sz[j];
if(sz[son[u]] < sz[j]) son[u] = j;
}
}
void dfs2(int u, int father)
{
f[u] = w[u];
for(int i = h[u]; ~i ; i = ne[i])
{
int j = e[i];
if(j == father) continue;
dfs2(j, u);
f[u] += f[j];
}
}
int lca(int u, int depth)
{
for(int k = 25 ; k >= 0 ; k -- )
{
if(dep[fat[u][k]] >= depth)
u = fat[u][k];
}
return u;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
memset(h, -1, sizeof h);
for(int i = 1 ; i < n ; i ++ )
{
int a, b;
cin >> a >> b;
add(a, b), add(b, a);
}
dfs1(1, 0);
for(int i = 1 ; i <= n ; i ++ ) cin >> d[i];
for(int i = 1 ; i <= n ; i ++ )
{
int tar = dep[i] - d[i];
tar = max(1ll, tar);
int t = lca(i, tar);
w[fa[t]] -- ;
w[i] ++ ;
}
dfs2(1, 0);
for(int i = 1 ; i <= n ; i ++ )
cout << f[i] << ' ';
cout << endl;
}