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} aibi1,而其中必须要有一个怪兽来启动这个环,所以我们需要付出直接代价 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 11 n2 3 2 4 2 n1
    故我们可将其分成 n n n个区间,其中前 n n n个区间的元素是 2 × ( n − i ) 2\times (n -i) 2×(ni)个。那么根据第 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(q3e5)次询问,每次询问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)=uu不断变成 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;
}
posted @ 2022-03-26 16:48  unique_pursuit  阅读(44)  评论(0)    收藏  举报