D. The Strongest Build(set&优先队列&结构体里面有数组)

题目:http://codeforces.com/contest/1574/problem/D

题意:有n组数,每一组有C[i]个数,每一组组内已经从小到大排好序,然后现在让你在每一组里面选出一个数,让他们的和最大,输出你选每一组里面的下标,现在你肯定想,选每一组里面最大的就可以了,确实这是最大的答案。但是现在又有m个限制条件,每一个限制条件,给出n个数,这n个数对应每一组,组里面的下标,然后这个组合是不能被选为答案的。
题目保证输入合法,并且保证一定存在一个组合可以作为答案(每一组都要有被选上的数),如果有多个方案,输出任意一个即可。
3
3 1 2 3
2 1 5
3 2 4 6
2
3 2 3
3 2 2
样例辅助理解,总共有3组,第一组有3个数,第二组有2个数,第三组有3个数;然后有2个组合是被限制的,限制1:第一组的第3个数,第二组的第二个数,第三组的第三个数,限制2:第一组的第三个数,第二组的第二个数,第三组的第二个数。这俩个组合是不能被选为答案的。首先如果没有限制的话,最大值肯定是第一组的第三个数,第二组的第二个数,第三组的第三个数,答案为3 2 3(下标),但是这一组下标不能作为答案,所以不行。

题解:解法及其暴力,思想也很简单,但是代码可能不太好实现。
首先,注意到n很小,如果n<=2的话,那就直接将限制的方案全部放入set里面存好,然后从小到大枚举所有的方案,看看它是不是不在限制里面即可,枚举可以用一个优先队列实现,把s(选出来的数的和)大的放前面,然后取出最大的,因为n<=2,所以优先队列里面最多插入2个数,类似最短路的思想,跑出答案即可,这是n<=2的时候,pair就可以解决。
但是n虽然很小,但还是很容易大于2的,这个时候可以大胆一点,开一个结构体,里面放一个数组,存n组的信息,相当于把2扩大到10,然后把这个结构体存入set和优先队列里面,让他们去比较这个数组是否存在过,事实证明,可以实现,细节在代码中。

时间复杂度:因为是把一个长度为10的数组放入到了set和优先队列中,时间复杂度不太好说了,姑且认为是只有一个数的时候的10倍吧。
首先se存限制方案,顶多是1e5个,所以时间复杂度是:1e5 * 10 * log(1e5)
优先队列中,因为限制顶多是1e5个,所以优先队列也顶多是1e5级别的,所以时间复杂度也大概是:1e5 * 10 * log(1e5)
is的作用是判断跑优先队列的时候,是否出现过这个组合,所以is是跟优先队列是的大小是一样的。
因为优先队列那里实在不好说明有多少个,但是绝对不会超过1e6个,就一定能出答案,所以姑且认为1e6是最坏答案吧,这样那么它的时间复杂度的顶层是 1e6 * 10 * log(1e5),题目给的3秒,所以不超时。

#include <bits/stdc++.h>
// #define int long long
#define pb push_back
#define pii pair<int, int>
#define mpr make_pair
#define ms(a, b) memset((a), (b), sizeof(a))
#define x first
#define y second
typedef long long ll;
typedef unsigned long long LL;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
using namespace std;
struct node {
    int a[11];  //存n组,分别选了哪一组的下标,a[i],i是第几组
    int s;//a[i]是选了这一组中的哪个下标。     s是选中的这n组数的和
};
int n;
//set所需要的从小到大排序
bool operator<(const node A, const node B) {
    if (A.s < B.s)
        return 1; //因为set是要判断存不存在的,所以下面这个
    //数组的判断必须有,不然它比较的时候只看s是否相等,不看数组是否相等
    //不信可以测一测
    else if (A.s == B.s) {
        for (int i = 1; i <= n; i++) {
            if (A.a[i] < B.a[i])
                return 1;
            else if (A.a[i] > B.a[i])
                return 0;
        }
    }
    return 0;
}
bool operator>(const node A, const node B) {
    if (A.s > B.s)
        return 1;   //因为优先队列没有判是否存在,所以下面也不需要,
        //只需要根据s来判断选中的数组的大小即可
    // else if (A.s == B.s) {
    //     for (int i = 1; i <= n; i++) {
    //         if (A.a[i] > B.a[i])
    //             return 1;
    //         else if (A.a[i] < B.a[i])
    //             return 0;
    //     }
    // }
    return 0;
}
//记录每一组里面有多少个数
int len[12];
// m个限制存入se中, is是跑优先队列的时候,判断这个组合是否出现过
set<node> se, is;  
//优先队列是从最大的组合开始跑,类似最短路一样,每次选取最大的
priority_queue<node> que;
//存n组的信息
vector<int> vec[12];
signed main() {
    scanf("%d", &n);
    //每一组先插入一个0,方便后面下标的处理
    for (int i = 0; i <= n; i++) vec[i].emplace_back(0);
    for (int i = 1; i <= n; i++) {
        int k;
        scanf("%d", &k);
        len[i] = k;
        for (int j = 0; j < k; j++) {
            int data;
            scanf("%d", &data);
            vec[i].emplace_back(data);
        }
    }
    int m;
    scanf("%d", &m);
    for (int i = 1; i <= m; i++) {
        node temp;
        temp.s = 0;
        for (int j = 1; j <= n; j++) {
            int data;
            scanf("%d", &data);
            temp.a[j] = data;
            temp.s += vec[j][data];
        }
        //将所有的限制组合插入的se中
        se.insert(temp);
    }
    node temp;
    temp.s = 0;
    for (int i = 1; i <= n; i++) temp.a[i] = len[i], temp.s += vec[i][len[i]];
    //得到最大的组合,插入到优先队列中,并且插入到is中,证明这个数列已经出现过
    is.insert(temp);
    que.push(temp);
    while (que.size()) {
        temp = que.top();
        que.pop();   //弹出
        //如果找到一个没被限制的方案,直接跳出,输出答案
        if (!se.count(temp)) {
            break;
        }
        //将这个组合中的某一个数替换一个比它小的
        for (int i = 1; i <= n; i++) {
            if (temp.a[i] != 1) { //如果这一组的下标已经是1了,就不能再替换小的了
                //修改下标和他们的和
                temp.s = temp.s - vec[i][temp.a[i]] + vec[i][temp.a[i] - 1];
                temp.a[i] -= 1; //下标减1
                if (!is.count(temp)) { //判断是否出现过,没出先过的话,就插入
                    is.insert(temp), que.push(temp);
                } 
                temp.a[i] += 1; //再还原,给下一个循环使用
                temp.s = temp.s + vec[i][temp.a[i]] - vec[i][temp.a[i] - 1];
            }
        }
    }
    //输出答案
    for (int i = 1; i <= n; i++) printf("%d ", temp.a[i]);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
将下面matlab代码function [channel] = preRun(acqResults, settings)%% Initialize all channels ================================================ channel = []; % Clear, create the structure channel.PRN = 0; % PRN number of the tracked satellite channel.acquiredFreq = 0; % Used as the center frequency of the NCO channel.codePhase = 0; % Position of the C/A start channel.codeFreq = 0; % Used as the center frequency of the code NCO channel.status = &#39;-&#39;; % Mode/status of the tracking channel % &quot;-&quot; - &quot;off&quot; - no signal to track % &quot;T&quot; - Tracking state %--- Copy initial data to all channels ------------------------------------ channel = repmat(channel, 1, settings.numberOfChannels); %% Copy acquisition results =============================================== %--- Sort peaks to find strongest signals, keep the peak index information [~, PRNindexes] = sort(acqResults.peakMetric, 2, &#39;descend&#39;); %--- Load information about each satellite -------------------------------- % Maximum number of initialized channels is number of detected signals, but % not more as the number of channels specified in the settings. for ii = 1:min([settings.numberOfChannels, sum(acqResults.carrFreq ~= 0)]) channel(ii).PRN = PRNindexes(ii); channel(ii).acquiredFreq = acqResults.carrFreq(PRNindexes(ii)); channel(ii).codePhase = acqResults.codePhase(PRNindexes(ii)); channel(ii).codeFreq = settings.codeFreqBasis + ... (channel(ii).acquiredFreq - settings.IF)/... settings.carrFreqBasis * settings.codeFreqBasis; % Set tracking into mode (there can be more modes if needed e.g. pull-in) channel(ii).status = &#39;T&#39;; end转成python
最新发布
06-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值