【10.22校内测试】【二分】【二分图】【很像莫队的乱搞/树状数组】

Solution

谁能想到这道题卡读入??还卡了70pts???

二分+$n^2$check就行了

Code

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

int n, m;
int sum[2005][2005];

void read(int &x) {
    x = 0; char ch = getchar();
    while(ch > ‘9‘ || ch < ‘0‘)    ch = getchar();
    while(ch >= ‘0‘ && ch <= ‘9‘) {
        x = x * 10 + ch - ‘0‘;
        ch = getchar();
    }
}

bool check(int mid) {
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= m; j ++) {
            int x = i - mid, y = j - mid;
            if(x < 0 || y < 0)    continue;
            int tmp = sum[i][j] - sum[x][j] - sum[i][y] + sum[x][y];
            if(tmp == mid * mid)    return 1;
        }
    return 0;
}

int erfen() {
    int ans = 0, l = 0, r = min(n, m);
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(check(mid))    ans = mid, l = mid + 1;
        else    r = mid - 1;
    }
    return ans;
}

int main() {
    freopen("inspect.in", "r", stdin);
    freopen("inspect.out", "w", stdout);
    read(n); read(m);
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= m; j ++) {
            int a;
            read(a);
            sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a;
        }
    int ans = erfen();
    printf("%d", ans);
    return 0;
}

Solution

谁能想到这道题标程错误??又卡了70pts!

正解二分图/网络流,就是最小路径覆盖问题。

标程错在没判重!

(我判了哼

Code

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

struct QAQ {
    int x, y;
} book[305], a[305];
bool cmp(QAQ a, QAQ b) { if(a.y == b.y)    return a.x > b.x;    return a.y > b.y; }

struct Node {
    int v, nex;
    Node(int v = 0, int nex = 0) :
        v(v), nex(nex) { }
} Edge[90005];

int stot, h[1005];
void add(int u, int v) {
    Edge[++stot] = Node(v, h[u]);
    h[u] = stot;
}

bool check(int i, int j) {
    if(book[i].x >= book[j].x && book[i].y >= book[j].y)    return 1;
    return 0;
}

int vis[1005], to[1005], pi[1005];
bool dfs(int u) {
    for(int i = h[u]; i; i = Edge[i].nex) {
        int v = Edge[i].v;
        if(!vis[v]) {
            vis[v] = 1;
            if(!to[v] || dfs(to[v])) {
                to[v] = u;
                pi[u] = v;
                return 1;
            }
        }
    }
    return 0;
}

int n;
int main() {
    freopen("militarytraining.in", "r", stdin);
    freopen("militarytraining.out", "w", stdout);
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) {
        scanf("%d%d", &book[i].x, &book[i].y);
    }
    sort(book + 1, book + 1 + n, cmp);
    for(int i = 1; i <= n; i ++)
        for(int j = i + 1; j <= n; j ++) {
            if(check(i, j))
                add(i, j + n);
        }
    int ans = 0;
    for(int i = 1; i <= n; i ++) {
        if(!pi[i]) {
            memset(vis, 0, sizeof(vis));
            ans += dfs(i);
        }
    }
    printf("%d", n - ans);
    return 0;
}

Solution

今天唯一一道有水平并且T得心甘情愿的题!

卡莫队啊~

所以就乱搞了QAQ

很容易知道满足条件的数k一定不超过O(sqrt(n))个,所以对于70%的数据可以暴力统计有哪些数出现次数超过它本身,之后每次询问查询这些数有多少在该区间内满足要求。(可以用多一个sqrt(n)的空间复杂度换取询问少一个log)

但对于100%的数据,显然不是超时就是炸空间。

考虑将询问按左端点排序,从右向左做。(然而我(zyl dalao!)从左往右)

维护一个数组t,t[i]表示如果询问区间包含了点i,答案会增加t[i](可能为负)。

初始情况下t全为0,i从n枚举到1,对某个i,考虑a[i]这个数在i位置及其以后是否出现过a[i]次及以上,假设a[i]在位置x出现了第a[i]次,在位置y出现了第a[i]+1次,即表示对于左端点为i的询问区间,当右端点在[x,y)时,a[i]会贡献1的答案,否则贡献0的答案,此时设t[x]=1且t[y]=-1即可。

用一个树状数组维护t数组,可以很容易的统计前缀和。

复杂度为O(nlogn+qlogn+qlogq)。

Code

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

int n, q, a[1000005];
int pre[1000005], cnt[1000005];

void read(int &x) {
    x = 0; char ch = getchar();
    while(ch > ‘9‘ || ch < ‘0‘)    ch = getchar();
    while(ch >= ‘0‘ && ch <= ‘9‘) {
        x = x * 10 + ch - ‘0‘;
        ch = getchar();
    }
}

struct Node {
    int l, r, ans, id;
} qus[1000005];
bool cmp(Node a, Node b) { return a.l < b.l; }
bool cmp2(Node a, Node b) { return a.id < b.id; }

int lowbit(int x) {
    return x & -x;
}

void add(int pos, int d) {
    for(int i = pos; i <= n; i += lowbit(i))
        pre[i] += d;
}

int query(int pos) {
    int ans = 0;
    for(int i = pos; i; i -= lowbit(i))
        ans += pre[i];
    return ans;
}

void modify(int l, int r, int d) {
    if(r < l)    return ;
    add(l, d);    add(r + 1, -d);
}

int t[1000005], st[1000005], nex[1000005], las[1000005];
void init(int x) {
    if(cnt[x] < x)    return ;
    t[x] = st[x];
    for(int i = 1; i < x; i ++)
        t[x] = nex[t[x]];
    modify(t[x], nex[t[x]] - 1, 1);
}

void change(int x) {
    if(cnt[x] < x)    return ;
    modify(t[x], nex[t[x]] - 1, -1);
    t[x] = nex[t[x]];
    if(t[x] == n + 1) {
        cnt[x] = -1;    return ;
    }
    modify(t[x], nex[t[x]] - 1, 1);
}

int main() {
    freopen("count.in", "r", stdin);
    freopen("count.out", "w", stdout);
    scanf("%d%d", &n, &q);
    for(int i = 1; i <= n; i ++) {
        read(a[i]);
        if(!las[a[i]]) st[a[i]] = i;
        nex[las[a[i]]] = i;
        nex[i] = n + 1;
        las[a[i]] = i;
        cnt[a[i]] ++;
    }
    for(int i = 1; i <= q; i ++)
        read(qus[i].l), read(qus[i].r), qus[i].id = i;
    sort(qus + 1, qus + 1 + q, cmp);
    for(int i = 1; i <= n; i ++)    init(i);
    int L = 1;
    for(int i = 1; i <= q; i ++) {
        while(L < qus[i].l) {
            change(a[L]);
            L ++;
        }
        qus[i].ans = query(qus[i].r);
    }
    sort(qus + 1, qus + 1 + q, cmp2);
    for(int i = 1; i <= q; i ++)    printf("%d\n", qus[i].ans);
    return 0;
}


分手快乐日! 祝我和自己百年好合!

原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9831024.html

时间: 2024-10-06 17:00:28

【10.22校内测试】【二分】【二分图】【很像莫队的乱搞/树状数组】的相关文章

HDU 6318 Swaps and Inversions 思路很巧妙!!!(转换为树状数组或者归并求解逆序数)

Swaps and Inversions Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2315    Accepted Submission(s): 882 Problem Description Long long ago, there was an integer sequence a.Tonyfang think this se

hdu5249---KPI(二分+树状数组)

Problem Description 你工作以后, KPI 就是你的全部了. 我开发了一个服务,取得了很大的知名度.数十亿的请求被推到一个大管道后同时服务从管头拉取请求.让我们来定义每个请求都有一个重要值.我的KPI是由当前管道内请求的重要值的中间值来计算.现在给你服务记录,有时我想知道当前管道内请求的重要值得中间值. Input 有大约100组数据. 每组数据第一行有一个n(1≤n≤10000),代表服务记录数. 接下来有n行,每一行有3种形式 "in x": 代表重要值为x(0≤

HDU2852 KiKi&#39;s K-Number 树状数组+二分

这题就是给了你三种操作, 1:往容器中一个元素 x 2::把容器中的元素x删除 3:查询比 x大的第k个数 想法:添加元素跟删除元素  直接是以数本身为序号然后以 value值为1和-1即可,相当于计数,至于找比x第k个大的数,那就看看当前往后数k个数的第一个数是哪个就可以了,一开始直接找出来,然后往后暴力的扫了一遍,结果错了,没关系,反应很快,直接改了个二分查找,然后就过了,弄清楚如何建立这个树状数组即可 #include<iostream> #include<cstdio> #

HDU 5592 ZYB&#39;s Premutation(树状数组+二分)

题意:给一个排列的每个前缀区间的逆序对数,让还原 原序列. 思路:考虑逆序对的意思,对于k = f[i] - f[i -1],就表示在第i个位置前面有k个比当前位置大的数,那么也就是:除了i后面的数字之外,它是在剩下的数字当中第k+1大的. 知道这个之后,可以用树状数组来帮助找出剩下的数中第k大的数,刚开始我们可以让1-n中每个元素都标记为1,那么他们的前缀和就代表它是第几小.所以,我们可以对于他们的和来二分快速寻找第k大数.其实在树状数组里面是按照第(i-k)小来找的.找完之后要删除这个元素的

csp-s模拟测试56(10.2)Merchant「二分」&#183;Equation「树状数组」

又死了......T1 Merchant 因为每个集合都可以写成一次函数的形式,所以假设是单调升的函数,那么随着t越大就越佳 而单调减的函数,随着t的增大结果越小,所以不是单调的??? 但是我们的单调只需凭借t时刻的sum值是否大于S即可 如果某个单减的集合符合情况,那么他在t==0时就符合情况 如果不符合,那么他就不会作出贡献 所以可以二分 T2 Equation 一开始以为是高斯消元??? 当然不是..... 把每个xi均用x1表示,那么我们发现,对于深度奇偶不同的点,他的表示方式是不同的,

13年山东省赛 Boring Counting(离线树状数组or主席树+二分or划分树+二分)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud 2224: Boring Counting Time Limit: 3 Sec  Memory Limit: 128 MB Description In this problem you are given a number sequence P consisting of N integer and Pi is the ith element in the sequence.

Educational Codeforces Round 10 D. Nested Segments (树状数组)

题目链接:http://codeforces.com/problemset/problem/652/D 给你n个不同的区间,L或者R不会出现相同的数字,问你每一个区间包含多少个区间. 我是先把每个区间看作整体,按照R从小到大排序.然后从最小的R开始枚举每个区间,要是枚举到这个区间L的时候,计算之前枚举的区间有多少个Li在L之后,那么这些Li大于L的区间的数量就是答案.那我每次枚举的时候用树状数组add(L , 1) 说明在L这个位置上出现了区间,之后枚举的时候计算L之前的和,然后i - 1 -

POJ 2828 Buy Tickets (线段树 or 树状数组+二分)

题目链接:http://poj.org/problem?id=2828 题意就是给你n个人,然后每个人按顺序插队,问你最终的顺序是怎么样的. 反过来做就很容易了,从最后一个人开始推,最后一个人位置很容易就确定了,那最后第二个人的位置也可以推(与最后一个人的位置无关)...依次就都可以确定所有的人了. 用前缀和的思想,要是这个人的位置确定了,那么就标记这个人位置的值为0,然后回溯更新,跟求逆序对个数的思想比较类似. 线段树: 1 #include <iostream> 2 #include &l

【BZOJ3110】【整体二分+树状数组区间修改/线段树】K大数查询

Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M 接下来M行,每行形如1 a b c或2 a b c Output 输出每个询问的结果 Sample Input 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 Sample Output 1 2 1 HINT