CF GYM 100703I Endeavor for perfection

题意:有n个学习领域,每个领域有m个课程,学习第i个领域的第j个课程可以获得sij个技能点,在每个领域中选择一个课程,要求获得的n个技能点的最大值减最小值最小,输出符合要求的策略。

解法:尺取法。将课程的技能点按值进行排序,同时要记录每个值对应的领域,用尺取法选择第一段包含全部领域的区间,区间的边界即为最值,然后将左指针逐步右移,直到出现有的领域没有选课,继续右移右指针,直到结束。当右指针已移到最右的时候需要特判,只移动左指针。

代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
#include<limits.h>
#include<time.h>
#include<stdlib.h>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define LL long long
using namespace std;
int c[205];
struct node
{
    int a, b, c;
    bool operator < (const node &tmp) const
    {
        if(a == tmp.a)
            return b < tmp.b;
        return a < tmp.a;
    }
    bool operator == (const node &tmp) const
    {
        return a == tmp.a && b == tmp.b;
    }
    node(int a, int b, int c) : a(a), b(b), c(c){}
    node() {}
};
vector <node> v;
int n;
bool judge(int cnt[])
{
    for(int i = 0; i < n; i++)
        if(!cnt[i])
            return false;
    return true;
}
int main()
{
    while(~scanf("%d", &n))
    {
        v.clear();
        for(int i = 0; i < n; i++)
        {
            scanf("%d", &c[i]);
        }
        if(n == 1 && c[0] == 1) //需要特判否则RE
        {
            int x;
            scanf("%d", &x);
            printf("0\n1\n");
            continue;
        }
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < c[i]; j++)
            {
                int s;
                scanf("%d", &s);
                v.push_back(node(s, i, j + 1));
            }
        }
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());
        int len = v.size();
        int flag = 0;
        int now = -1;
        int cnt[205] = {0};
        int l = 0, r = 0;
        cnt[v[0].b] = 1;
        int ans = INT_MAX, pl, pr;
        for(; l < len;)
        {
            if(!flag)
            {
                r++;
                cnt[v[r].b]++;
                if(judge(cnt))
                {
                    flag = 1;
                    if(v[r].a - v[l].a < ans)
                    {
                        ans = v[r].a - v[l].a;
                        pl = l, pr = r;
                    }
                    continue;
                }
            }
            else
            {
                if(~now && r < len - 1)
                {
                    r++;
                    cnt[v[r].b]++;
                    if(cnt[now])
                    {
                        now = -1;
                        if(v[r].a - v[l].a < ans)
                        {
                            ans = v[r].a - v[l].a;
                            pl = l, pr = r;
                        }
                    }
                }
                else
                {
                    if(r == len - 1)
                    {
                        cnt[v[l].b]--;
                        l++;
                        if(judge(cnt))
                        {
                            if(v[r].a - v[l].a < ans)
                            {
                                ans = v[r].a - v[l].a;
                                pl = l, pr = r;
                            }
                        }
                        continue;
                    }
                    cnt[v[l].b]--;
                    if(!cnt[v[l].b])
                    {
                        now = v[l].b;
                        l++;
                    }
                    else
                    {
                        l++;
                        if(v[r].a - v[l].a < ans)
                        {
                            ans = v[r].a - v[l].a;
                            pl = l, pr = r;
                        }
                    }
                }
            }
        }
        printf("%d\n", ans);
        int prt[205];
        for(int i = pl; i <= pr; i++)
        {
            prt[v[i].b] = v[i].c;
        }
        for(int i = 0; i < n; i++)
        {
            if(i)
                printf(" ");
            printf("%d", prt[i]);
        }
        puts("");
    }
    return 0;
}

  

时间: 2024-11-06 07:35:44

CF GYM 100703I Endeavor for perfection的相关文章

CF gym 101933 K King&#39;s Colors —— 二项式反演

题目:http://codeforces.com/gym/101933/problem/K 其实每个点的颜色只要和父亲不一样即可: 所以至多 i 种颜色就是 \( i * (i-1)^{n-1} \),设为 \( f(i) \),设恰好 i 种颜色为 \( g(i) \) 那么 \( f(i) = \sum\limits_{j=0}^{i} C_{i}^{j} * g(j) \) 二项式反演得到 \( g(i) = \sum\limits_{j=0}^{k} (-1)^{k-j} * C_{k}

CF Gym 101955G Best ACMer Solves the Hardest Problem

链接:https://codeforces.com/gym/101955/problem/G 题意:在二维平面上四种操作: 1,加一个带权的点: 2,删去一个点: 3,给一个点周围欧几里得距离为sqrt(k)的存在的点点权都加w: 4,查询一个到点欧几里得距离为sqrtk的点权和. x, y<6000, k<1e7, sigma(询问次数)<1e6,time:12s 题解:原本以为是数据结构,发现距离为k的x,y其实不多,直接存vector<pii>dis[maxk]暴力即可

CF Gym 102059E Electronic Circuit (set存图删点)

链接:https://codeforces.com/gym/102059/problem/E 题意:n个点, m条线,问这个电路是否合法,合法:可以确定一个起点和一个终点. 题解:不断的删点,删除度数为2的点,再相连,看最终度数为1的点的个数是否为2.set存图 #include <bits/stdc++.h> using namespace std; const int maxn=3e5+5; set<int> S[maxn]; int n, m; void del_edge()

cf Gym 101086M ACPC Headquarters : AASTMT (Stairway to Heaven)

题目: Description standard input/output As most of you know, the Arab Academy for Science and Technology and Maritime Transport in Alexandria, Egypt, hosts the ACPC Headquarters in the Regional Informatics Center (RIC), and it has been supporting our r

cf gym 100960 G. Youngling Tournament set+树状数组

G. Youngling Tournament time limit per test 2 seconds memory limit per test 256 mebibytes input standard input output standard output Yoda, the Grand Master of the Jedi Order, hit on the idea to hold a tournament among younglings. He has not chosen t

CF Gym 100187A Potion of Immortality

根据兔子试药情况可以缩小范围,如果死了,不在试过的药里面,如果活着,在试过的药里. 最糟的情况: 两个原则 1.能确定药所在的范围的尽量大,2.死得兔子尽量多. 如果当前不知道情况的药n为k的二倍以上,那么基于上面两个原则,试过药的兔子肯定会死. 没死:范围k,损失的兔子0 死了:范围n-k,损失的兔子1 (n>2*k) 设r=n%k,经过上述过程,损失了n/k-1只兔子,转移到了当前状态范围w = k+r, 1.r == 0 那么可以补充一个毒药,变成w=k+1,根据鸽巢原理再死一个就可以确定

CF Gym 100500A Poetry Challenge

题解:暴力dfs,如果有一个选择,能让对手必败,那么就是必胜态,能转移到的状态都是对手的必胜态,或者无法转移,就是必败态. 总算是过了,TLE是因为状态没判重,不过我还是有一点没想明白,为什么状态会出现重复 #include<cstdio> #include<cmath> #include<vector> #include<map> #include<set> #include<algorithm> #include<iostr

CF Gym 100187D Holidays

题意:给n个元素,从n中选两个非空集合A和B.问有多少中选法? 以下错误示范: 我推的O(n^2)神公式,公式正确,然并卵. 递推就行了 dp[n]表示元素个数为n的方案数,对于新来的一个元素,要么加入集合,要么不加入集合自成一个集合.加入集合有三种选择,A,B,E(全集 和 A和B的并 的差集,可空),或者自成集合,作为A或B,然后在选一个n-1个元素的非空子集(2^n-1 - 1).(注意,不能作为E,因为不作为A和B,按定义应归到E里面) 还有组合做法,有点复杂,待学习 #include<

CF Gym 100187B A Lot of Joy

题意:给两个一样的只含有26个小写字母的字符串,然后两个分别做一下排列,问如果对应位置的字母相等那么就愉悦值就加一,问愉悦值的期望是多少? 题解:只考虑两个序列相对的位置,那么就相当于固定一个位置,另外一个序列做排列.对于一个字符,假设是a,然后a有Na个,那么a选第一个序列中a对应的位置,发生这个事件的概率为1*(n-1)!/n!,1是选那个位置,(n-1)!是其他的元素排列,n!是总的情况. 学习点:将问题拆分,一个一个考虑对答案的贡献值. #include<cstdio> #includ