A. Cowardly Rooks
题目大意:给你一个n×n的棋盘和m个棋子,并且给出初始的摆放状态,棋子会攻击所在行和所在列,问你能不能够将一个棋子移动到别的位置并且各个棋子之间不相互攻击,题目给出的摆放状态一定不会相互攻击
分析:观察就能够发现,能不能移动棋子只和n和m有关系,当n != m是,一定存在某一行或者某一列不会被攻击到,所以将任意一个棋子移动到该位置即可;如果n == m,那么此时棋盘一定被这m个棋子限制的刚刚好,没有办法再移动任何棋子。同时题目给出的摆放方式一定是可行的,所以不用担心会出现m > n的情况
#include <bits/stdc++.h>
using namespace std ;
const int N = 3e5 + 8 ;
const int mod = 998244353 ;
using ll = long long ;
void solve()
{
int n , m ;
cin >> n >> m ;
int x ;
for(int i = 0 ; i < m ; i ++){
cin >> x >> x ;
}
cout << (n != m ? "YES" : "NO") << '\n' ;
}
int main(){
std::ios::sync_with_stdio(false) ;
std::cin.tie(0) ;
int T ;
cin >> T ;
while(T --){
solve() ;
}
return 0 ;
}
B. Death's Blessing
题目大意:有一排怪物需要打,并且每个怪物都有a的血量一个技能,在怪物死后会给相邻的两个怪物加上b的血量(最两边的怪物只有一个相邻的怪物),并且击杀怪物需要a的血量,问你能够击杀掉所有的怪物所需要花费的最小值
分析:因为击杀一个怪物会给相邻的两个怪物加上b的血量,但是两边的怪物只有一个相邻的怪物,也就是说杀掉两边的怪物得到的花费肯定是比杀掉中间的怪物总花费要小的。也就是说我们的策略就是不断地击杀两边的怪物中回血较少的那一个,所以说最终我们的总花费就是所有的a加上所有的b减去b中的最大值,因为我们将回血量最大的那个留在最后杀,这样总花费是最小的
#include <bits/stdc++.h>
using namespace std ;
const int N = 2e5 + 8 ;
const int mod = 998244353 ;
using ll = long long ;
int b[N] ;
void solve()
{
int n ;
cin >> n ;
int a ;
ll ans = 0 ;
for(int i = 0 ; i < n ; i ++){
cin >> a ;
ans += a ;
}
for(int i = 0 ; i < n ; i ++){
cin >> b[i] ;
ans += b[i] ;
}
sort(b , b + n) ;
ans -= b[n - 1] ;
cout << ans << '\n' ;
}
int main(){
std::ios::sync_with_stdio(false) ;
std::cin.tie(0) ;
int T ;
cin >> T ;
while(T --){
solve() ;
}
return 0 ;
}
C. Number Game
题目大意:Alice和Bob在玩游戏,首先选定一个值k,每次Alic可以删去一个小于k - i + 1的值,Bob可以任意选择一个数加上k - i + 1,每个回合Alice删掉一个,Bob选择一个数加上一个值。如果在k个回合之内,如果Alice无法删掉任何一个数,那Alice就输了,如果Alice能活过k个回合,那Alice就胜利,要求找出最大的k
分析:Bob肯定每次选择对最小的数加上k - i + 1,增加它不能被删除的几率,而Alice每次肯定删除能删除的最大的数,因为题目的数据范围非常小,所以从大到小枚举k的值即可
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std ;
const int N = 108 ;
using ll = long long ;
int a[N] , b[N] , n ;
bool vis[N] ;
/*
Alice : 删除 <= k - i + 1
Bob : 随便增加 k - i + 1
*/
bool judge(int k){
memcpy(b , a, sizeof b) ;
for(int i = 1 ; i <= k ; i ++){
sort(b + 1 , b + n + 1) ;
int pos = lower_bound(b + 1 , b + n + 1 , k - i + 1) - b ;
if(b[pos] == k - i + 1) b[pos] = inf ;
else{
pos -- ;
if(pos == 0) return false ;
else b[pos] = inf ;
}
sort(b + 1 , b + n + 1) ;
b[1] += k - i + 1 ;
}
return true ;
}
void solve(){
cin >> n ;
memset(vis , false , sizeof vis) ;
for(int i = 1 ; i <= n ; i ++) {
cin >> a[i] ;
}
for(int k = n ; k >= 0 ; k --){
if(judge(k)){
cout << k << '\n' ;
return ;
}
}
}
int main(){
std::ios::sync_with_stdio(false) ;
std::cin.tie(0) ;
int T ;
cin >> T ;
while(T --){
solve() ;
}
return 0 ;
}
D. Counting Arrays(补)
题目大意:给出一个数组a,如果
,那么就可以把a[i]删除,然后还有一个“删除数组b”,也就是每次按照数组b中的顺序来删除a中对应的数,每次删除了a中的一个数后将a中被删除后面的数都往左移动一格。定义a数组是一个"模棱两可"的数组当且仅当a数组的删除数组不唯一。问有多少个长度1-n的,取值为整数1-m的数组
分析:我们可以分析得到[1,1,1,1,1]一定是一个删除数组,也就是说只要数组有除了[1,1,1,1,1,1]以外的删除数组就是一个模棱两可的数组。直接求有点困难,我们先求出所有不模棱两可的数组,然后用所有的数组减去不模棱两可的数组即是答案。因为[1,1,1,1,1,1...]一定是一个删除数组,如果某一个位置i的数跟所有(2 ~ i)的所有数都不互质,那么我们就无法删除它,用tmp代表从1 ~ i中的所有质数的乘积,那
就是能取到的所有值
思路参考:Educational Codeforces Round 138 (Rated for Div. 2) A - D - 知乎 (zhihu.com)
#include <bits/stdc++.h>
using namespace std ;
const int N = 3e5 + 8 ;
const int mod = 998244353 ;
using ll = long long ;
ll primes[N] , cnt ;
bool st[N] ;
ll n , m ;
ll a[N] , b[N] ;
void init() {
for(int i = 2 ; i < N ; i ++ ) {
if(!st[i]) primes[cnt ++ ] = i;
for(int j = 0; primes[j] * i < N ; j ++ ) {
st[primes[j] * i] = true;
if(i % primes[j] == 0) break;
}
}
}
ll gcd(ll a , ll b){
return b > 0 ? gcd(b , a % b) : a ;
}
ll lcm(ll a, ll b) {
return a * b / gcd(a, b);
}
void solve()
{
cin >> n >> m ;
init() ;
ll lc = 1 ;
a[1] = m % mod ;
for(ll i = 2 ; i <= n ; i ++){
if(!st[i]) lc = lcm(lc , i) ;
ll cnt = m / lc ;
a[i] = (a[i - 1] * (cnt % mod)) % mod ;
}
b[1] = m % mod ;
for(int i = 2 ;i <= n ; i ++){
b[i] = (b[i - 1] * (m % mod)) % mod ;
}
ll ans = 0 ;
for(int i = 1 ; i <= n ; i ++){
ans = (ans + b[i] - a[i]) % mod ;
}
cout << ans % mod << '\n' ;
}
int main(){
std::ios::sync_with_stdio(false) ;
std::cin.tie(0) ;
solve() ;
return 0 ;
}
EF太菜了不会
(水平有限,欢迎指正)