平时十三测

今天是真NOIP难度的题

第一题:单调栈原题,但被读优卡成了30,以后一定要注意读入问题

#include<bits/stdc++.h>
using  namespace std;
const int M = 2005;
int a[M][M], up[M][M];
struct node{int w, h;}q[M];
int read(){
    int x = 0; int f = 1; char c = getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
    return x*=f;
}

int main(){
    //freopen("cc.in","r",stdin);
    freopen("inspect.in","r",stdin);
    freopen("inspect.out","w",stdout);
    int n, m, ans = 0;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)a[i][j] = read();
    for(int i = n; i; i--)
        for(int j = 1; j <= m; j++)
            up[i][j] = a[i][j] ? up[i+1][j] + 1 : 0;
    for(int st = 1; st <= n; st++){
        int h = 1, t = 1;
        q[1].w = 1, q[1].h = up[st][1];
        for(int i = 2; i <= m; i++){
            int w = 0;
            while(h <= t && up[st][i] <= q[t].h){
                w += q[t].w;
                ans = max(ans, min(w, q[t].h));
                t--;
            }
            q[++t] = (node) {1 + w, up[st][i]};
        }
        int w = 0;
        while(h <= t){
            w += q[t].w;
            ans = max(ans, min(w, q[t].h));
            t--;
        }        
    }
    
    printf("%d\n", ans);
} 
View Code

 

第二题:开始想贪心,看到数据觉得可能不是,然后感觉好像方格取数加强版,就上了一波费用流,其实就是最基本的最小链覆盖;

但是后来有人贪心过了,把x排序以后不就变成了导弹拦截。。。

#include<bits/stdc++.h>
using  namespace std;
const int N = 705, M = 3e5, inf = 1e9;
int tot = 1, S, T, SS;
int h[N], dis[N], px[N], py[N], pre[N], pree[N], n;
bool inq[N];
struct zz{int x,y;}qq[N];
bool cmp(zz A, zz B){return A.x == B.x ? A.y < B.y : A.x < B.x;}
struct edge{int v, nxt, w, pf, f;}G[M];
void add(int u, int v, int f, int w){
    G[++tot].v = v, G[tot].nxt = h[u], G[tot].w = w, G[tot].pf = G[tot].f = f, h[u] = tot;
    G[++tot].v = u, G[tot].nxt = h[v], G[tot].w = -w, G[tot].pf = G[tot].f = 0, h[v] = tot;
}
#define RG register
queue <int> q;
bool spfa(){
    memset(dis, 0x8f, sizeof(dis));
    memset(pre, 0, sizeof(pre));
    memset(pree, 0, sizeof(pree));
    dis[SS] = 0, inq[SS] = 1;
    q.push(SS);
    while(!q.empty()){
        int u=q.front();q.pop();inq[u]=0;
        for(RG int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            if(G[i].f && dis[v] < dis[u] + G[i].w){
                dis[v] = dis[u] + G[i].w;
                pre[v] = u, pree[v] = i;
                if(!inq[v])q.push(v), inq[v] = 1;
                //fprintf(stderr, "%d %d %d %d %d\n", u, v, dis[u], dis[v], G[i].w);
            }
        }
    }
    return dis[T] > 0;
}


int check(int k){
    G[tot].f = 0, G[tot^1].f = k;
    int ret = 0;
    for(int i = 1; i <= tot - 2; i++)G[i].f = G[i].pf;
    while(spfa()){
        int u = T, del = inf;
        while(u != SS){
            del = min(del, G[pree[u]].f);
            u = pre[u];
        }
        u = T;
        while(u != SS){
            G[pree[u]].f -= del;
            G[pree[u]^1].f += del;
            u = pre[u];
        }
        ret += dis[T]*del;
    }
    return ret;
}

int main(){
    //freopen("cc.in","r",stdin);
    freopen("militarytraining.in","r",stdin);
    freopen("militarytraining.out","w",stdout);
    scanf("%d", &n);
    S = 0, T = 2 * n + 1, SS = T + 1;
    for(int i = 1; i <= n; i++)
        scanf("%d%d", &qq[i].x, &qq[i].y);
    sort(qq + 1, qq + 1 + n, cmp);
    int cnt = 0;
    for(RG int i = 1; i <= n; i++)
        if(qq[i].x == qq[i-1].x && qq[i].y == qq[i-1].y)continue;
        else px[++cnt] = qq[i].x, py[cnt] = qq[i].y;
    for(RG int i = 1; i <= cnt; i++)
        for(RG int j = 1; j <= cnt; j++)
            if(i != j && px[i] <= px[j] && py[i] <= py[j])
                add(i + n, j, inf, 0);
    for(RG int i = 1; i <= cnt; i++){
        add(S, i, 1, 0);
        add(i + n, T, 1, 0);
        add(i, i + n, 1, 1);
    }
    add(SS, S, 0, 0);
    int lf = 1, rg = cnt, ans = 0;
    while(lf <= rg){
        int mid = (lf + rg) >> 1;
        if(check(mid) == cnt) ans = mid, rg = mid - 1;
        else lf = mid + 1;
    }    
    printf("%d\n", ans);
}
View Code

 

第三题:思维好题

考虑将询问按左端点排序,从右向左做。
维护一个数组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)。

#include<bits/stdc++.h>
using namespace std;
const int M = 1e6 + 5;
int lst[M], a[M], n, c[M], ans[M], cnt[M], que[M], gx[M];
vector <int> vec[M];
#define RG register
struct node{int l, r, id;}q[M];
bool cmp(node A, node B){
    return A.l < B.l;
}

int read(){
    int x = 0; int f = 1; char c = getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
    return x*=f;
}
void add(int x, int d){
    for(; x <= n; x += x&(-x))
        c[x] += d;
}
int query(int x){
    int ret = 0;
    for(; x; x -= x&(-x))
        ret += c[x];
    return ret;
}
int main(){
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    n = read();int Q = read(), tot = 0;
    for(RG int i = 1; i <= n; i++){
        a[i] = read();
        cnt[a[i]]++;
        vec[a[i]].push_back(i);
    }
    for(RG int i = 1; i <= n; i++)
        if(cnt[i] >= i)que[++tot] = i, gx[i] = 1;
    for(RG int i = 1; i <= tot; i++){
        int u = que[i];
        if(vec[u].size() == u) add(vec[u][u-1], 1);
        else {
            add(vec[u][u-1], 1);
            add(vec[u][u], -1);
        }
        lst[u] = u;
    }
    for(RG int i = 1; i <= Q; i++)
        q[i].l = read(), q[i].r = read(), q[i].id = i;
    sort(q + 1, q + 1 + Q, cmp);
    
    int lf = 0;
    for(RG int i = 1; i <= Q; i++){
        while(lf < q[i].l){
            lf++;
            int u = a[lf-1];
            if(!gx[u])continue;
            if(lst[u] == (int)vec[u].size()){
                add(vec[u][lst[u]-1], -1);
                lst[u]++;
            }
            else if(lst[u] == (int)vec[u].size()-1){
                add(vec[u][lst[u]-1], -1);
                add(vec[u][lst[u]], 2);
                lst[u]++;
            }
            else if(lst[u] <= (int)vec[u].size()-2){
                add(vec[u][lst[u]-1], -1);
                add(vec[u][lst[u]], 2);
                add(vec[u][lst[u]+1], -1);
                lst[u]++;
            }
        
        }
        
        ans[q[i].id] = query(q[i].r);
    }
    for(int i = 1; i <= Q; i++)printf("%d\n", ans[i]);
}
View Code

 

posted @ 2018-10-22 17:15  Ed_Sheeran  阅读(147)  评论(0)    收藏  举报