题目整理0

  • CF750D

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

  • CF750E

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

  • CF754D

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
题解:
假定

  • 状态0 为只能匹配到空串,
  • 状态1为只能匹配到"2"** 不能匹配到更多**
  • 状态2为只能匹配到"20"** 不能匹配到更多**
  • 状态3为只能匹配到"201"** 不能匹配"2016" 和 "2017"**
  • 状态4为只能匹配到"2017"** 不能匹配到"2016"**

定义一个字符串区间对应的矩阵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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容