ABC203

C

题意:有从0开始编号的村子0, 1, 2, 3, ..., 一开始taro在0号,有k元,每去一个村子需要花费1元,taro有N个朋友,分别站在N个村子,当taro到第i个朋友站的村子的时候,第i个朋友会给他ki元,问taro能走到的最大编号是多少

方法:模拟或者二分(一开始想复杂了)

#include<iostream>
#include<algorithm>

using namespace std;

#define int long long

const int N = 2e5 + 10;

int n, k;

struct node{
    int a, b;
    bool operator<(const node &n){
        return a < n.a;
    }
}a[N];

signed main(){
    cin >> n >> k;
    for(int i = 1; i <= n; i ++) cin >> a[i].a >> a[i].b;
    sort(a + 1, a + 1 + n);
    int res = k, i = 0;
    while(res >= a[i].a){
        res += a[i].b;
        i ++;
        if(i > n) break;
    }
    cout << res;
}

D

题意:给你一个NxN网格g,每一个网格上有一个数字,问这个网格中所有大小为KxK的子矩阵中最小能达到的中位数的值是多少

方法:二分答案,如果存在一个K^2的网格使得中位数小于等于x,那么所有>= x的值均能满足条件,所以满足二段性,一定能找到最小的x,另外就是check函数复杂度的问题,如果直接暴力去找每一个K^2大小的矩阵的中位数再和x比的话是\(O((N-K+1)^2K^2)\), 肯定T,因为check函数需要判断是否存在一个k^2大小的矩阵使得它的中位数<= x, 所以只需要对每一个k^2大小的矩阵判断他里面> x的数的个数是否满足< k^2 / 2就行了,这里可以用提前标记+前缀和来做,复杂度\(O(N^2log1e9)\)

#include<iostream>
using namespace std;

const int N = 810;

int n, k;
int a[N][N], st[N][N];

int check(int x){
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n; j ++)
            st[i][j] = a[i][j] > x;
    
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n; j ++)
            st[i][j] += st[i - 1][j] + st[i][j - 1] - st[i - 1][j - 1];
    
    for(int i = 1; i <= n - k + 1; i ++)
        for(int j = 1; j <= n - k + 1; j ++){
            int p = i + k - 1, q = j + k - 1;
            int val = st[p][q] - st[i - 1][q] - st[p][j - 1] + st[i - 1][j - 1];
            if(val < k * k / 2 + 1) return 1;
        }
        
    return 0;
}

int main(){
    cin >> n >> k;
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n; j ++)
            cin >> a[i][j];
    
    int l = 0, r = 1e9;
    while(l < r){
        int mid = l + r >> 1;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    
    cout << l << endl;
}

类似的题:https://codeforces.com/contest/1288/problem/D

题意:给你n个序列\(a_1, a_2, ..., a_n\),每一个序列长为m(m <= 8),任选序列ai和aj构成b,令bk = max(aik, ajk),问能够构成的序列b中最小值最大为多少

方法:二分答案,注意如果再check函数里面直接枚举i和j然后求b看是否能够找到这样的b它的最小值>= x,复杂度\(O(N^2)\)过不了,方法是对于ai计算一个数字t,如果ai是5,4,3,2,1,而x = 3,那么ai所得到的数字是\(t=(11100)_2\),就是只要是aik满足>= x就令t的从高向低的第k位为1,因为m很小,所以对于所有的ai,计算得到的数字数不超过2m,将所有得到的数字存起来,然后枚举其中的任意两个数,如果满足两者相或为2m - 1,那么就说明通过这两个序列得到的序列b满足最小值>= x,直接返回1即可

#include<iostream>
#include<algorithm>
#include<map>

using namespace std;

const int N = 3e5 + 10;

int a[N][10];

int n, m;
pair<int, int> ans{1, 1};

int check(int x){
    map<int, int> mp;
    for(int i = 1; i <= n; i ++){
        int t = 0;
        for(int j = 1; j <= m; j ++)
            t = t * 2 + (a[i][j] >= x);
        mp[t] = i;
    }

    for(auto i : mp)
        for(auto j : mp)
            if((i.first | j.first) == (1 << m) - 1){
                ans = {i.second, j.second};
                return 1;
            }
                 
    return 0;
}

int main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= m; j ++)
            cin >> a[i][j];
    
    int l = 0, r = 1e9;
    while(l < r){
        int mid = l + r + 1 >> 1;
        if(check(mid)) l = mid;
        else r = mid - 1;
    }
    
    cout << ans.first << ' ' << ans.second << endl;
}
posted @ 2021-11-03 22:07  yys_c  阅读(48)  评论(0编辑  收藏  举报