A. Grid Ice Floor**
这道题要去考虑能访问到的格子(i,j)的状态,我们发现只有5种,即当我们在格子(i,j)时,此时的运动状态为:
- 方向往上
- 方向往下
- 方向往左
- 方向往右
- 停下来
因此我们就设dp[i][j][0/1/2/3/4/5]表示到达格子(i,j),此时状态是上述5种中的一个,这个情况是否发生,转移就根据当前状态,枚举后继状态转移即可。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
vector<string> tu(n);
for (auto& i : tu)
cin >> i;
vector<vector<array<int, 5>>> ok(n,
vector<array<int, 5>>(m, array<int, 5>{}));
queue<array<int, 3>> team;
array<int, 4> dx{1, -1, 0, 0};
array<int, 4> dy{0, 0, 1, -1};
team.push({1, 1, 2});
team.push({1, 1, 0});
ok[1][1][0] = ok[1][1][2] = ok[1][1][4] = 1;
auto stop = [&](int x, int y) { return tu[x][y] == '#'; };
while (!team.empty())
{
auto [x, y, d] = team.front();
team.pop();
if (d == 4)
{
for (int i = 0; i < 4; ++i)
{
int nx = x + dx[i], ny = y + dy[i];
if (!stop(nx, ny) && !ok[nx][ny][i])
{
team.push({nx, ny, i});
ok[nx][ny][i] = 1;
}
}
continue;
}
int nx = x + dx[d], ny = y + dy[d];
if (stop(nx, ny))
{
if (!ok[x][y][4])
{
team.push({x, y, 4});
ok[x][y][4] = 1;
}
} else
{
team.push({nx, ny, d});
ok[nx][ny][d] = 1;
}
}
int ans = 0;
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
{
bool access = false;
for (auto& k : ok[i][j])
access |= k;
ans += access;
}
cout << ans << '\n';
return 0;
}
B. Strictly Superior/
这道题就是去枚举每一个可能,判断是否符合题意即可。然后用bitset去优化时间。
#include<stdio.h>
#include<bitset>
using namespace std;
bitset<110>a[100010];
int b[100010];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i=1;i<=n;i++)
{
int c;
scanf("%d%d", &b[i], &c);
for (int j=1;j<=c;j++)
{
int x;
scanf("%d", &x);
a[i][x] = 1;
}
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
if(i!=j)
{
if (b[i]<=b[j])
{
bitset<110>t=a[i]&a[j];
if (t==a[j]&&(b[i]<b[j]||t!=a[i]))
{
printf("Yes\n");
return 0;
}
}
}
}
}
printf("No\n");
return 0;
}
C. Reversible /
这道题就是用set<string>去存储字符串,然后去记录去重后的字符串长度就行。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<set>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const LL P = 131;
char ch[200010];
set<ULL>st;
ULL get_hash(int n);
int main()
{
int n;
scanf("%d", &n);
for (int i=1;i<=n;i++)
{
scanf("%s", ch+1);
int len=strlen(ch+1);
ULL x=get_hash(len);
reverse(ch+1, ch+1+len);
ULL y=get_hash(len);
if(st.find(x)==st.end()&&st.find(y)==st.end())
st.insert(x);
}
printf("%lld", st.size());
return 0;
}
ULL get_hash(int n)
{
ULL h=0;
for (int i=1;i<=n;i++)
h = h*P+ch[i];
return h;
}
D. Find it!**
这道题题意的构图方式实际是一棵或多棵基环内向树,其特点是从任意一个点出发,必定会跑到环内。
故而随便从一个点进行DFS,记录一下每个点是否被访问过,当一个点第二次访问时,它就是环上的点。然后从它遍历一下得到环上的点即可。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
vector<int> to(n);
for (int i = 0; i < n; ++i)
{
int v;
cin >> v;
--v;
to[i] = v;
}
int u = 0;
vector<int> visit(n);
for (u = 0; !visit[u]; u = to[u])
{
visit[u] = 1;
}
vector<int> ans{u};
for (int i = to[u]; i != u; i = to[i])
{
ans.push_back(i);
}
cout << ans.size() << '\n';
for (auto& i : ans)
cout << i + 1 << ' ';
cout << '\n';
return 0;
}
E. Vacation Together
这道题就是先用一个二维数组来存储所以字符串,然后按列去遍历这个二维数组,如果没有出现x就c++,然后用maxc去记录最大的c值,即为连续最多有几个o。
#include<stdio.h>
#include<math.h>
using namespace std;
int main()
{
int n, d;
scanf("%d%d", &n, &d);
char a[n][d+1];
for(int i=0;i<n;i++)
{
scanf("%s", a[i]);
}
int c=0, maxc=-1;
int k;
for(int j=0;j<d;j++)
{
k=0;
for(int i=0;i<n;i++)
{
if(a[i][j]=='x')
k=1;
}
if(k==0)
c++;
if(k==1)
c=0;
maxc=max(maxc, c);
}
printf("%d\n", maxc);
return 0;
}
F. Number Box**
这道题的思路就是:两个负数无论相差多选都可以相互抵消,一个0可以抵消任意多个任意距离的负数,所以去统计矩阵中负数出现的个数和标记0是否出现即可。奇数个负数时,使整个矩阵最小的数为唯一负数即可。
G. Jumping Takahashi 2**
这道题我在网上看的思路就是二分答案,然后暴力建图 dfs 就行了。虽然就这短短一句话,但我感觉难度还是挺大的,对我来说。
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
for(;(c<'0'||c>'9');c=getchar()){if(c=='-')f=-1;}
for(;(c>='0'&&c<='9');c=getchar())x=x*10+(c&15);
return x*f;
}
const int MN=205;
int x[MN],y[MN];
vector<int>G[MN];
int dis(int i,int j)
{
return abs(x[i]-x[j])+abs(y[i]-y[j]);
}
int n,p[MN];
const int INF=5e9;
bool vis[MN];
void dfs(int u)
{
vis[u]=1;
for(int v:G[u])if(!vis[v])dfs(v);
}
bool chk(int v)
{
for(int i=1;i<=n;i++)G[i].clear();
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j)continue;
if(dis(i,j)<=p[i]*v)G[i].push_back(j);
}
}
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
dfs(i);bool pd=1;
for(int k=1;k<=n;k++)if(!vis[k])pd=0;
if(pd)return 1;
}
return 0;
}
signed main(void)
{
n=read();
for(int i=1;i<=n;i++)x[i]=read(),y[i]=read(),p[i]=read();
int L=0,R=INF,ans=INF;
while(L<=R)
{
int mid=(L+R)>>1;
if(chk(mid))R=mid-1,ans=mid;
else L=mid+1;
}
cout<<ans<<endl;
return 0;
}
H. When?
这道题没什么难度,因为就21和22两个时间,主要就是%02d用来输出个位数的时间。
#include<stdio.h>
int main()
{
int k;
scanf("%d", &k);
if(k<60)
{
printf("21:%02d", k);
}
else
{
printf("22:%02d", k-60);
}
return 0;
}
I. Rotation
这道题一开始我是想用string s去存储数据,然后在1的时候用s.insert()去把最后一个字符移到最前面,然后再读取目标字符,结果超时了。。。
然后改为用sx去记录到底移动了多少次,因为每移动原字符串长度次,那么就会又变为原字符串,故此时sx=sx%n。然后再去数目标字符到底在哪。
#include<stdio.h>
int main()
{
int n, q;
scanf("%d%d", &n, &q);
char a[n+1];
scanf("%s", a);
long long sx=0;
for(int i=0;i<q;i++)
{
int x1, x2;
scanf("%d%d", &x1, &x2);
if(x1==1)
{
sx+=x2;
}
if(x1==2)
{
if(sx/n>0)
{
sx=sx%n;
}
if(sx>=x2)
{
printf("%c\n", a[n-sx+x2-1]);
}
else
{
printf("%c\n", a[x2-sx-1]);
}
}
}
return 0;
}
J. Trophy**
K. Many Oranges
这道题就是按题目条件的要求去写就是。
#include <stdio.h>
int main()
{
int a, b, w;
scanf("%d%d%d", &a, &b, &w);
w*=1000;
int min, max;
if(w%b==0)
{
min=w/b;
}
else
{
min=w/b+1;
}
max=w/a;
if(min > max)
{
printf("UNSATISFIABLE\n");
}
else
{
printf("%d %d\n", min, max);
}
return 0;
}
L. Alcoholic
这道题就是去判断什么是v*p/100>x,但要注意的就是用除非来进行判断可能出现误差,我就是因为这个没有过,呜呜难受。。。所以要用v*p>x*100。
#include<stdio.h>
int main()
{
int n, x, sx=0;
scanf("%d%d", &n, &x);
for(int i=0;i<n;i++)
{
int v, p;
scanf("%d%d", &v, &p);
sx+=v*p;
if(sx>x*100)
{
printf("%d", i+1);
return 0;
}
}
printf("-1");
return 0;
}