文章目录
一、A. Cowardly Rooks
- 思路: 从题目可以得出,m <= n,因为前面都给排好了,所以如果m == n,不管移动哪一个都不行,反之如果m < n,就移动某一行或者某一列为空的相邻行和列中的物品
- 代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define int long long
#define pb push_back
#define endl '\n'
#define all(x) x.begin(),x.end()
#define PII pair<int,int>
using namespace std;
const int N = 2e5 + 100,mod=998244353;
bool st[10][10];
void solve()
{
int n,m; cin >> n >> m;
for(int i = 1;i <= m;i ++ )
{
int x,y; cin >> x >> y;
}
if(m >= n) cout << "NO" << endl;
else cout << "YES" << endl;
}
signed main()
{
ios::sync_with_stdio(false); cin.tie(0);
int T; cin >> T;
while(T -- ) solve();
}
二、B - Death’s Blessing
- 思路: 因为A数组中的所有元素肯定要加上去,我们遍历一边数组发现,不管从哪一个开始,只会留一个b[i],没有被便利,所以贪心来看,就让b[i]最大的最后便利,排个序就行
- 代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define int long long
#define pb push_back
#define endl '\n'
#define all(x) x.begin(),x.end()
#define PII pair<int,int>
using namespace std;
const int N = 2e5 + 100,mod=998244353;
bool st[10][10];
void solve()
{
int n,m; cin >> n;
int sum = 0;
for(int i = 1;i <= n;i ++ )
{
int x;
cin >> x;
sum += x;
}
int mx = -1;
for(int i = 1;i <= n;i ++ )
{
int x; cin >> x;
mx = max(mx,x);
sum += x;
}
cout << sum - mx << endl;
}
signed main()
{
ios::sync_with_stdio(false); cin.tie(0);
int T; cin >> T;
while(T -- ) solve();
}
三、C - Number Game
思路: A操作越多,能够选择的数字越少,所以贪心来看,就让A尽量选择大的删除,同时B为了不让A操作过多,贪心来看,就尽量在元素值小的地方加上去,这样给a数组排序,因为k最大是(n + 1) / 2,n <= 100,所以直接暴力枚举k的取值,当然二分也行,然后看看在当前的k下,是否满足条件
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define int long long
#define pb push_back
#define endl '\n'
#define all(x) x.begin(),x.end()
#define PII pair<int,int>
using namespace std;
const int N = 2e5 + 100,mod=998244353;
int a[110];
void solve()
{
int n,m; cin >> n;
int d = 0; // k最大是n + 1 / 2;
for(int i = 1;i <= n;i ++ ) cin >> a[i];
sort(a + 1,a + 1 + n);
for(int k = (n + 1) / 2;k >= 1;k -- )
{
int u = k;
int d = 0;
int i = 1,j = n;
while(i <= j)
{
while(j >= i && a[j] > u) j--;
if(j >= i && a[j] <= u)
{
d++;
j--;
}
else
break;
u--;
i++;
}
if(d >= k)
{
cout << k << endl;
return;
}
}
cout << "0" << endl;
//如果数组中没有1,那就是0
// 如果有1个1,答案就是1
// 如果有两个1,答案就是2
}
signed main()
{
ios::sync_with_stdio(false); cin.tie(0);
int T; cin >> T;
while(T -- ) solve();
}
四、D - Counting Arrays
- 思路: 我们发现计算符合的条件个数太多,于是我们可以计算不符合的条件个数,然后让总数 - 不符合的条件个数,不管什么排列,最少都有一次,[1,1,1,1,1,1…],如果不想这个排列有至少两次,
对于a[2],那就必须符合gcd(a[2],2) != 1,
对于a[3],就必须符合gcd(a[3],3) != 1,并且gcd(a[3],2) != 1,也就是说a[3] 必须得是 2和3的倍数
对于a[4], 就必须符合gcd(a[4],4) != 1,并且gcd(a[4],3) != 1并且gcd(a[4],2) != 1,a[4],也必须是2,3,4的倍数,但是4已经是2的倍数,所以就是质数的倍数,就行
对于a[n],就必须符合gcd(a[n],n) != 1,并且gcd(a[n],n - 1) != 1…gcd(a[n],2) != 1
对于a[i],就必须让i这个位置上面的数字是i的倍数,同时也是i - 1的倍数…同时也是2的倍数,那我们就用他们的质因数来求解就行
观察这个规律发现,在 i 对于 i 这个位置,如果 i 是 合数,那不用动,如果 i 是质数,那就必须使得 tmp = tmp * i,那在这个位置不能选的数字数量是 m / tmp,用w来存当前长度为 i 不能选的排列数量 那对于当前长度为 i 且不能选的排列数就是 w = w * (m ./ tmp),最后求一遍全部的排列数量 减去不能选的排列个数即可 - 代码:
#include <bits/stdc++.h>
#define int long long
#define PII pair<int,int>
using namespace std;
const int N = 2e5 + 100,mod = 998244353;
int p[N],cnt;
bool st[N];
void init()
{
for(int i = 2;i <= N;i ++ )
{
if(!st[i])
p[cnt++] = i;
for(int j = 0;p[j] <= N / i;j ++ )
{
st[i * p[j]] = true;
if(i % p[j] == 0) break;
}
}
}
int quick(int a,int b)
{
int k = 1;
a %= mod;
while(b)
{
if(b & 1)
{
k = k * a % mod;
}
b = b >> 1;
a = a * a % mod;
}
return k;
}
void solve()
{
int n,m; cin >> n >> m;
int tmp = 1;
int w = m % mod,res =0;
int y = m % mod;
for(int i = 2;i <= n;i ++ ) // 要知道每一个a[i],有多少种选法使得
{
if(!st[i] && tmp <= m) // 质数
tmp = tmp * i;
w = (w * ((m / tmp) % mod)) % mod; // 不超过1e12
res = (res + w) % mod;
}
int ans = 0;
for(int i = 2;i <= n;i ++ )
ans = (ans + quick(m,i)) % mod;
cout << (ans + mod - res) % mod<< endl;
}
signed main()
{
init();
int T = 1;
while(T -- ) solve();
return 0;
}
四、E - Cactus Wall
- 思路: 观察发现,假设没有仙人掌,那放的方式就是交叉放置,也就是必须得斜着走,走的方式还得满足 |xi - xi-1| = |yi - yi-1| = 1,否则肯定不行,那问题就转化为求从(x , 1)到 (y, m)的最短路径,同时权值也是只有0 和 1,权值为 0 的时候,就是当前位置走到的位置是 仙人掌,否则权值就是1,这里就用双端队列来求解就行,然后记录前驱,注意细节 ,这里面建立动态数组,建立静态会 ME
- 代码:
#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define fi first
#define se second
#define ios ios::sync_with_stdio(false),cin.tie(0)
#define PII pair<int,int>
using namespace std;
const int N = 4e5 + 100,mod = 1e9 + 7,INF = 1e9;
int n,m;
int dx[4] = {-1, -1, 1, 1}, dy[4] = {-1, 1, -1, 1};
bool check(string *s,int x,int y)
{
if(x < 1 || x > n || y < 1 || y > m) return false;
if(x + 1 <= n && s[x + 1][y] == '#') return false;
if(x - 1 >= 1 && s[x - 1][y] == '#') return false;
if(y + 1 <= m && s[x][y + 1] == '#') return false;
if(y - 1 >= 1 && s[x][y - 1] == '#') return false;
return true;
}
void solve()
{
cin >> n >> m;
string s[n + 1];
for(int i = 1;i <= n;i ++ ) cin >> s[i],s[i] = "?" + s[i];
deque<PII> q;
vector<vector<PII> > pre(n + 2,vector<PII> (m + 2));
vector<vector<int> > dist(n + 2,vector<int> (m + 2,INF));
for(int i = 1;i <= n;i ++ )
{
if(s[i][1] == '#') // 权值为0
{
dist[i][1] = 0;
q.push_front({i,1});
}
else if(check(s,i,1))
{
dist[i][1] = 1;// 权值为1
q.push_back({i,1});
}
}
while(q.size())
{
auto t = q.front();q.pop_front();
for(int i = 0;i < 4;i ++ )
{
int x = dx[i] + t.fi,y = dy[i] + t.se;
if(check(s,x,y)) // 代表当前这个点能走
{
if(dist[t.fi][t.se] + (s[x][y] != '#') < dist[x][y])
{
pre[x][y] = {t.fi,t.se};// 记录前驱
dist[x][y] = dist[t.fi][t.se] + (s[x][y] != '#');
if(s[x][y] == '#')
q.push_front({x,y});
else
q.push_back({x,y});
}
}
}
}
// 寻找前驱
int x = 0,y = 0;
int ans = INF;
for(int i = 1;i <= n;i ++ )
{
if(ans > dist[i][m])
{
ans = dist[i][m];
x = i,y = m;
}
}
if(ans == INF) cout << "NO" << endl;
else
{
cout << "YES" << endl;
while(1)
{
if(s[x][y] == '.') s[x][y] = '#';
if(y == 1) break;
auto p = pre[x][y];
x = p.fi;
y = p.se;
}
for(int i = 1;i <= n;i ++ )
{
for(int j = 1;j <= m;j ++ )
cout << s[i][j];
cout << endl;
}
}
}
signed main()
{
ios; int T; cin >> T;
while(T -- ) solve();
return 0;
}