题目整理0

2017-01-09  本文已影响18人  TimeMage

tag: DP, 二维数组映射二维平面的方法

tag: 矩阵,状态转移,结合律,线段树

tag: 贪心,排序,优先队列


CF750D

题目链接: http://codeforces.com/contest/750/problem/D
题解:如果每条线段以一个带起点的向量表示的话,每个阶段有2^n个向量
但是平面的最大范围为300*300,所以有很多向量起点相同,而且一个起点
最多只有8个方向把它们合并起来就行了。复杂度 (30*300*300*8*5)

平面到二维数组的映射方法

bool va[MAXV][MAXV];
bool (*vis)[MAXV] = (bool (*)[MAXV])(va[150]+150);

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define sf scanf
#define pf printf
const int MAXV = 301; 
const int MAXN = 32;
int dir[8][2] = {0,1,-1,1,-1,0,-1,-1,0,-1,1,-1,1,0,1,1};
int db[MAXV][MAXV][MAXN];
bool va[MAXV][MAXV];
int (*dirst)[MAXV][MAXN] = (int (*)[MAXV][MAXN])(db[150]+150);
bool (*vis)[MAXV] = (bool (*)[MAXV])(va[150]+150);
int n, t;
void color(int x, int y, int t, int d) {
    for(int i=1; i<=t; ++i) {
        int tx = x+i*dir[d][0];
        int ty = y+i*dir[d][1];
        vis[tx][ty] = true;
    }
}
int main() {
    sf("%d", &n);
    dirst[0][0][0] = (1<<0);
    for(int step=1; step<=n; ++step) {
        sf("%d", &t);
        for(int x=-150; x<=150; ++x)
            for(int y=-150; y<=150; ++y) {
                for(int i=0; i<8; ++i) {
                    int ox = x-dir[i][0]*t;
                    int oy = y-dir[i][1]*t;
                    if(ox>=-150&&ox<=150&&oy>=-150&&oy<=150) {
                        if(dirst[ox][oy][step-1]&(1<<i)) {
                            color(ox,oy,t, i);
                            dirst[x][y][step] |= (1<<((i+7)%8));
                            dirst[x][y][step] |= (1<<((i+1)%8));
                        }
                    }
                }
            }
    }
    int cnt = 0;
    for(int i=-150; i<=150; ++i)
        for(int j=-150; j<=150; ++j)
            if(vis[i][j]) ++cnt;
    printf("%d\n", cnt);
    return 0;
}

CF750E

题目链接: http://codeforces.com/contest/750/problem/E
题解:
假定

定义一个字符串区间对应的矩阵a[i][j]为
当前面的区间为状态i时,附加上这段区间变为状态j所需要的代价
矩阵合并时可用矩阵乘法,且满足结合律
然后就可以用线段树划分区间做了
代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define sf scanf
#define pf printf
#define inf 0x3f3f3f3f
const int MAXN = 2e5+1e3;
struct Node{
    int a[5][5];
    int *operator [] (int x) {
        return a[x];
    }
    Node operator + (Node b) {
        Node c;
        memset(c.a, 0x3f, sizeof(c.a));
        for(int i=0; i<5; ++i)
            for(int j=0; j<5; ++j)
                for(int k=0; k<5; ++k)
                    c[i][j] = min(c[i][j], a[i][k]+b[k][j]);
        return c;
    }
}tr[MAXN<<2];
char str[MAXN];
int sl, sr;
Node build(int id, int l, int r) {
    if(l==r) {
        Node& e = tr[id];
        for(int i=0; i<5; ++i)
            for(int j=0; j<5; ++j)
                e[i][j] = (i==j)?0:inf;
        switch(str[l]) {
            case '2': 
                e[0][0] = 1;
                e[0][1] = 0;
                break;
            case '0':
                e[1][1] = 1;
                e[1][2] = 0;
                break;
            case '1':
                e[2][2] = 1;
                e[2][3] = 0;
                break;
            case '7':
                e[3][3] = 1;
                e[3][4] = 0;
                break;
            case '6':
                e[3][3] = 1;
                e[4][4] = 1;
                break;
        }
    }
    else {
        int m = l+r>>1;
        tr[id] = build(id<<1, l, m)+build(id<<1|1, m+1, r);
    }
    return tr[id];
}
Node query(int id, int l, int r) {
    if(sl<=l&&r<=sr) return tr[id];
    int m = l+r>>1;
    if(m>=sr) return query(id<<1, l, m);
    if(m<sl) return query(id<<1|1, m+1, r);
    return query(id<<1, l, m)+query(id<<1|1, m+1, r);
}
int main() {
    int n, q;
    sf("%d%d", &n, &q);
    sf("%s", str+1);
    build(1,1,n);
    while(q--) {
        sf("%d%d", &sl, &sr);
        int ans = query(1, 1, n)[0][4];
        if(ans==inf) puts("-1");
        else pf("%d\n", ans);
    }
    return 0;
}

CF754D

题目链接: http://codeforces.com/contest/754/problem/D
题解
<p>When we choose k coupons, (x1, y1), (x2, y2) ... (xk, yk), number of products we can use is minimum y — maximum x + 1. So we need maximize this value.</p>
<p>Sort initial points by y coordinate increasing. Let's say we are at position i. We can fix this point as the one with the minimum y, and we need to take k — 1 points from range [i + 1 ... n].</p>
<p>The k — 1 points must have maximum x coordinate as small as possible, in order to maximize the value (minimum y — maximum x + 1).
Let's iterate over all points in this order : n, n — 1.... 1, and maintain a heap / set with smallest K x coordinates we have met until now.</p>
<p>The answer for a position i would be : y coordinate of i-th point — largest value in the heap + 1.</p>
代码

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
#define sf scanf
#define pf printf
#define l first
#define r second
#define pb push_back
typedef pair<int,int> pr;
const int MAXN = 3e5+1e3;
int n, k, ans, cur;
pr seg[MAXN];
int id[MAXN];
struct cmpl{
    bool operator() (int a, int b) {
        return seg[a].l<seg[b].l;
    }
};
bool cmpr(int a, int b) {
    return seg[a].r<seg[b].r;
}
priority_queue<int, vector<int>, cmpl> pq;
void work(int st, int ed) {
    while(!pq.empty()) pq.pop();
    for(int i=st; i>=ed; --i) {
        pq.push(id[i]);
        if(pq.size()>k) {
            int x =pq.top();
            pq.pop();
            if(x==id[i]) continue;
        }
        if(pq.size()==k) {
            int x=pq.top();
            int len = seg[id[i]].r-seg[x].l+1;
            if(len>ans) {
                ans = len;
                cur = i;
            }
        }
    }
}
int main() {
    sf("%d%d", &n, &k);
    for(int i=0; i<n; ++i) {
        sf("%d%d", &seg[i].l, &seg[i].r);
        id[i] = i;
    }
    sort(id, id+n, cmpr);
    work(n-1,0);
    pf("%d\n", ans);
    work(n-1, cur);
    while(!pq.empty()) {
        pf("%d ", 1+pq.top());
        pq.pop();
    }
    puts("");
    return 0;
}
上一篇 下一篇

猜你喜欢

热点阅读