Educational Codeforces Round 85 (Rated for Div. 2) A~E题解
A. Level Statistics
-
题意
给你一个游戏时刻序列,其中每个时刻包含 p i , c i p_i,c_i pi,ci,代表游戏次数和通关次数。需要你判断序列是否合理。 -
解题思路
前一个时刻不能比当前时刻的参数小,并且通关次数的增长要小于游戏次数的增长。 -
AC代码
/**
*@filename:A
*@author: pursuit
*@created: 2021-08-13 09:00
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int t,n;
int x,y,p,c;
void solve(){
bool flag = false;
p = c = 0;
for(int i = 1; i <= n; ++ i){
scanf("%d%d", &x, &y);
if(x < p || y < c || y - c > x - p){
flag = true;
}
p = x, c = y;
}
printf("%s\n", flag ? "NO" : "YES");
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d", &n);
solve();
}
return 0;
}
B. Middle Class
-
题意
给你 n n n个数,你可以从中选取一些数然后做平均再分配。需要你判断最多有多少数可以 ≥ x \geq x ≥x。 -
解题思路
我们自然是想将多出来的分给其他数,那么选取的小于 x x x的也是尽量选择大的。所以我们可以对这些数排序,然后依次取前面的的数,知道平均数小于 x x x时则退出,那么前一个则是最大的答案。 -
AC代码
/**
*@filename:B
*@author: pursuit
*@created: 2021-08-13 09:35
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int t,n,x,a[N];
void solve(){
sort(a + 1, a + n + 1);
ll sum = 0;
int cnt = 0;
for(int i = n; i >= 1; -- i){
sum += a[i];
cnt ++;
if(1.0 * sum / cnt < x){
cnt --;
break;
}
}
printf("%d\n", cnt);
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d%d", &n, &x);
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
}
solve();
}
return 0;
}
C. Circle of Monsters
-
题意
有 n n n个环在一起的怪兽,其有生命值 a i a_i ai和爆炸伤害 b i b_i bi,即会对第 i + 1 i+1 i+1个怪兽产生 b i b_i bi的上海。问你要杀死这 n n n个怪兽所需的最小代价。 -
解题思路
我们首先要清楚,如果所有怪兽都要杀死,那杀死每个怪兽必然有要付出的代价就是 a i − b i − 1 a_i-b_{i-1} ai−bi−1,而其中必须要有一个怪兽来启动这个环,所以我们需要付出直接代价 a i a_i ai找到最小的即可。 -
AC代码
/**
*@filename:C
*@author: pursuit
*@created: 2021-08-13 09:42
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 3e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int t,n;
ll a[N],b[N],c[N];
void solve(){
ll sum = 0;
for(int i = 1; i <= n; ++ i){
sum += c[i];//必须要花费的消耗。
}
ll minn = 1e14;
for(int i = 1; i <= n; ++ i){
minn = min(minn,a[i] - c[i]);
}
printf("%lld\n", sum + minn);
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%lld%lld", &a[i], &b[i]);
if(i > 1)c[i] = a[i] - b[i - 1] < 0 ? 0 : a[i] - b[i - 1];
}
c[1] = a[1] - b[n] < 0 ? 0 : a[1] - b[n];
solve();
}
return 0;
}
D. Minimum Euler Cycle
-
题意
给你一个有向完全图,其中有 n n n个顶点,你需要使得每条边都走一遍,找到字典序最小的一种方案,并输出 [ l , r ] [l,r] [l,r]之间的结点。 -
解题思路
根据题意,我们可构造唯一的字典序最小的序列如:
1 2 1 3 1 4 1 … 1 n 2 3 2 4 … 2 n … 1 1\ 2 \ 1 \ 3 \ 1\ 4 \ 1\dots1 \ n\\2\ 3\ 2 \ 4 \dots \ 2 \ n \\ \dots \\1 1 2 1 3 1 4 1…1 n2 3 2 4… 2 n…1。
故我们可将其分成 n n n个区间,其中前 n n n个区间的元素是 2 × ( n − i ) 2\times (n -i) 2×(n−i)个。那么根据第 x x x个结点我们则可以确定在第 i i i个区间,而对于每个区间其中形式为 i i + 1 i i + 2 … i \ i +1\ i \ i +2 \dots i i+1 i i+2…,据此可得。 -
AC代码
/**
*@filename:D
*@author: pursuit
*@created: 2021-08-13 12:40
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int t,n;
ll l,r;
ll pre[N];
int cal(ll x){
if(x > pre[n - 1])return 1;//排除特殊情况。
int idx = lower_bound(pre + 1,pre + n + 1,x) - pre;
//那么pre就在idx所管辖的这个区间为 idx idx + 1 idx idx + 2...这种形式。
x = x - pre[idx - 1];
return x & 1 ? idx : x / 2 + idx;
}
void solve(){
for(int i = 1; i <= n; ++ i){
pre[i] = pre[i - 1] + 2 * (n - i);
}
for(ll i = l; i <= r; ++ i){
printf("%d%c", cal(i), " \n"[i == r]);
}
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d%lld%lld", &n, &l, &r);
solve();
}
return 0;
}
E. Divisor Paths
-
题意
给你一个数 D ( < = 1 e 15 ) D(<=1e15) D(<=1e15),D的所有因子(包括1和它本身)作为节点构成无向图,对于某两个因子 x x x, y y y,若 x % y = = 0 x\%y==0 x%y==0且 x / y x/y x/y为质数,那么x,y之间就存在一条长为 n u m ( x ) − n u m ( y ) num(x)-num(y) num(x)−num(y)的边,其中 n u m ( x ) num(x) num(x)代表 x x x的因子数量。接下来 q ( q ≤ 3 e 5 ) q(q\leq 3e5) q(q≤3e5)次询问,每次询问a,b,问a到b之间的最短路径有多少条。 -
解题思路
不难发现, a − > b a->b a−>b一定会经过 g c d ( a , b ) gcd(a,b) gcd(a,b)这个点,因为 a , b a,b a,b都整除 g c d ( a , b ) gcd(a,b) gcd(a,b)。 a a a不断变成 g c d ( a , b ) gcd(a,b) gcd(a,b)的过程中即是在不断除以质因子,所以我们可以看成 a / g c d ( a , b ) = u ( 假 设 这 个 数 为 u ) a/gcd(a,b)=u(假设这个数为u) a/gcd(a,b)=u(假设这个数为u)不断变成 1 1 1的方案数,即是 u u u的质因子的幂次之和的阶乘除以 u u u的每个质因子的幂次的阶乘之和。二者相乘即可。注意我们需要预处理阶乘和结点的方案数,提高效率。 -
AC代码
/**
*@filename:E
*@author: pursuit
*@created: 2021-08-13 14:03
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 998244353;
const int INF = 0x3f3f3f3f;
ll d,u,v;
int q,fac[N];
map<ll,ll> p;
void init(){
//预处理n!
fac[0] = fac[1] = 1;
for(int i = 2; i < N; ++ i){
fac[i] = 1LL * fac[i - 1] * i % P;
}
}
ll ksm(ll n,ll q){
ll ans = 1;
while(q){
if(q & 1)ans = ans * n % P;
n = n * n % P;
q >>= 1;
}
return ans;
}
ll cal(ll x){
//需要计算x到y的所有最短路径,而其都经过gcd(x,y)。
//x移动到gcd(x,y)的最短路径,就是x除以x/(gcd(x,y))的质因子,除的顺序是任意的。
ll sum1 = 0,sum2 = 1;
for(ll i = 2; i * i <= x; ++ i){
if(x % i == 0){
ll num = 0;
while(x % i == 0){
x /= i;
num ++;
}
sum2 = sum2 * ksm(fac[num], P - 2) % P;//除法取模边乘法。
sum1 += num;
}
}
if(x > 1){
sum1 ++;
}
sum1 = sum2 * fac[sum1] % P;
return sum1;
}
void solve(){
for(ll i = 1; i * i <= d; ++ i){
if(d % i == 0){
p[i] = cal(i);
p[d / i] = cal(d / i);
}
}
while(q -- ){
scanf("%lld%lld", &u, &v);
ll k = __gcd(u,v);
printf("%lld\n", p[u / k] * p[v / k] % P);
}
}
int main(){
init();
scanf("%lld%d", &d, &q);
solve();
return 0;
}

浙公网安备 33010602011771号