Educational Codeforces Round 85 (Rated for Div. 2)【ABCDE】(题解)

目录

涵盖知识点:思维、贪心、数学。

比赛链接:传送门

A - Level Statistics

题意: 按照时间顺序给出游戏进行次数和通关次数,判断是否合理。
题解: 保证相邻区间内和总区间进行次数大于等于通关次数且非递减即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;

int main(){
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        int maxp=0,maxc=0;
        bool flag=true;
        while(n--){
            int p,c;
            cin>>p>>c;
            if(p<maxp||c<maxc||p<c||p-maxp<c-maxc){
                flag=false;
            }
            maxp=max(p,maxp),maxc=max(c,maxc);
        }
        puts(flag?"YES":"NO");
    }
    return 0;
}

B - Middle Class

题意: 规定财富大于等于某个阈值即为有钱人,每次操作可以选取一堆人,让他们每个人的财富变为他们的平均值。
题解: 从大到小排序后贪心。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
ll a[maxn];
int main(){
    int t;
    cin>>t;
    while(t--){
        int n;
        ll x;
        cin>>n>>x;
        for(int i=1;i<=n;i++)cin>>a[i];
        sort(a+1,a+n+1);
        reverse(a+1,a+1+n);
        int cnt=0;
        ll sum=0;
        for(int i=1;i<=n;i++){
            sum+=a[i];
            if(sum>=x*i)cnt++;
            else break;
        }
        cout<<cnt<<"\n";
    }
    return 0;
}

C - Circle of Monsters

题意: 有一圈怪兽,每个怪兽有\(a_i\)点生命值,每射击1次怪兽会掉1点生命值,当怪兽死亡时会对下一个怪兽造成\(b_i\)点伤害,要想消灭所有怪兽最少需要射击多少次。
题解: 先把所有血量修到前一个怪死亡后会造成的伤害,然后选一个最少的把怪打死的伤害即可。
Accept Code: 学到了rotate的用法。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e6+10;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll a[maxn],b[maxn];
int main(){
    int t;
    cin>>t;
    while(t--){
        ll n,ans=inf,cnt=0;
        scanf("%lld",&n);
        for(int i=0;i<n;i++)scanf("%lld%lld",&a[i],&b[i]);
        rotate(b,b+n-1,b+n);
        for(int i=0;i<n;i++){
            if(a[i]>b[i])cnt+=a[i]-b[i];
        }
        for(int i=0;i<n;i++){
            ll res=0;
            if(a[i]>b[i])res-=(a[i]-b[i]);
            res+=a[i];
            ans=min(ans,res);
        }
        cout<<cnt+ans<<"\n";
    }
    return 0;
}

D - Minimum Euler Cycle

题意: 给定\(n\)个顶点的完全有向图。要求求出字典序最小的欧拉回路的某个区间。
题解: 观察题目中给的\(n=3\)的样例可以看出\(\left[ 1,2,1,3 \right] \left[ 2,3 \right] \left[ 1 \right]\)
就是说对\(1 \sim n\)的每一个节点,每次从当前点出发依次走到下一个节点再回来是字典序最小的,但是当前点走到\(n\)时不能回来,要直接走到下一个节点去,不然就会无路可走。最终才回到1节点
再观察可以发现对于\(1 \sim n\)节点,每组有\(2(n-i)\)个节点,同时奇数位的节点就是它本身,偶数位为当前组内位置除\(2+i\)
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int main(){
    int t;
    cin>>t;
    while(t--){
        ll n, l, r;
        cin>>n>>l>>r;
        ll limit = 1ll * n * (n - 1) + 1;
        ll sum = 0, id = 1;
        for (ll i = l; i <= r && i < limit; i++){
            while (sum + (n - id) * 2 < i)
                sum += (n - id) * 2, id++;
            ll d = i - sum;
            printf("%lld ", (d & 1) ? id : d / 2 + id);
        }
        if (r == limit)
            cout<<"1 ";
        cout<<"\n";
    }
}

E - Divisor Paths

题意:
给定一个正整数\(D\), 以此建图

  1. 每个节点都是\(D\)的因子
  2. \(x,y(x>y)\)节点之间有无向边存在的条件是\(y\)\(x\)因子且\(\frac{x}{y}\)是质数
  3. \(x,y\)之间若有边,则边权是\(x\)的因子中不是\(y\)的因子的个数
    给出\(q\)组询问,求\(u,v\)之间的最短路径条数

题解: 首先可以想到,一个节点\(u\)向另一个节点\(v\)转移的过程中总是通过抛出一些因子来进行的,其中\(v|u\)
那么uu到vv的最短路径就是\(d(u)-d(x_1)+d(x_1)-d(x-2)+\ldots+d(x_y)-d(v)=d(u)-d(v)\),其中\(d(x)\)\(x\)的因子个数,因此当一个节点能被令一个节点整除时,两节点间的最短路径就是两节点的因子个数之差。考虑到\(u\)\(v\)两者不为倍数关系时,因为节点的转移需要通过抛出一些因子来实现,所以需要找个中间节点\(x\)使得\(u->x\)并且\(v->x\),那么显而易见\(x\)肯定为\(u\)\(v\)的公因子,要使的路径最短就是使得\(d(u)-d(x)+d(v)-d(x)\)最小,那么就是使得\(d(x)\)最大,所以\(x=gcd(u,v)\),那么最终所求就是\(g(u,gcd(u,v))*g(v,gcd(u,v))\),其中\(g(u,v)\)\(u\)\(v\)两点间最短路径的条数
因为一个节点\(u\)向另一个节点\(v\)转移的过程中总是通过抛出一些因子来进行的,那么条数就是这些中间因子的抛出顺序,那么对于\(g(u,v)\),其中\(v|u\),令\(x=\frac{u}{v}\),则\(g(u,v)=\frac{t!}{p_1!*p_2!...p_n!}\),其中\(t\)\(x\)中各质因子的幂之和,\(p_i\)\(x\)中某个质因子的幂,就是排列组合里重复剔除问题除于它的阶乘
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
map<ll, ll> m;

ll calc(ll x){
    if (m[x])
        return m[x];
    ll res = 0, y = x;
    for (ll i = 2; i * i <= y; i++)
        if (y % i == 0){
            while (y % i == 0)
                y /= i;
            res = (res + calc(x / i)) % mod;
        }
    if (y > 1)
        res = (res + calc(x / y)) % mod;
    return m[x] = res;
}

int main(){
    ll d, q;
    cin>>d>>q;
    m[1] = 1;
    while (q--){
        ll u, v;
        cin>>u>>v;
        ll w = __gcd(u, v);
        printf("%lld\n", calc(u / w) * calc(v / w) % mod);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/charles1999/p/12683617.html