返回顶部

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

[toc]

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

比赛链接:传送门

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$是质数
  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$,则$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;
}
posted @ 2020-04-12 08:10  Charles1999  阅读(123)  评论(0编辑  收藏  举报