2017洛谷7月月赛总结

P3817 小A的糖果

    • 391通过
    • 1.3K提交
  • 题目提供者lin_toto
  • 标签
  • 难度普及-
  • 时空限制1s / 128MB

 提交  讨论  题解  

最新讨论更多讨论

  • 强烈要求加强数据
  • 30分,怎么办?急求助!!!…
  • 50分,求大牛
  • 这个小A的牙应该坏掉了吧
  • 数据有纰漏
  • 抢沙发~

题目描述

小A有N个糖果盒,第i个盒中有a[i]颗糖果。

小A每次可以从其中一盒糖果中吃掉一颗,他想知道,要让任意两个相邻的盒子中加起来都只有x颗或以下的糖果,至少得吃掉几颗糖。

输入输出格式

输入格式:

 

第一行输入N和x。

第二行N个整数,为a[i]。

 

输出格式:

 

至少要吃掉的糖果数量。

 

输入输出样例

输入样例#1:
3 3
2 2 2
输出样例#1:
1

输入样例#2:
6 1
1 6 1 2 0 4
输出样例#2:
11
输入样例#3:
5 9
3 1 4 1 5
输出样例#3:
0

说明

样例解释1

吃掉第二盒中的糖果。

样例解释2

第二盒吃掉6颗,第四盒吃掉2颗,第六盒吃掉3颗。

30%的测试数据,2<=N<=20,0<=a[i], x<=100

70%的测试数据,2<=N<=1000,0<=a[i], x<=10^5

100%的测试数据,2<=N<=10^5,0<=a[i], x<=10^9

分析:其实就是一道模拟题,枚举一次,对于每两盒相邻糖,在后一盒糖中减去比x多的数目,如果不够减,则在前一盒糖中减,其实根本不需要处理前一盒糖,只需要将后一盒糖的数量变成0即可,因为前一盒糖不再参与以后的运算了.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int n,x;
long long a[100010],sum;

int main()
{
    scanf("%d%d",&n,&x);
    for (int i = 1; i <= n; i++)
    scanf("%lld",&a[i]);
    for (int i = 1; i < n; i++)
    {
        if (a[i] + a[i + 1] > x)
        {
            sum += a[i] + a[i + 1] - x;
            a[i + 1] -= a[i] + a[i + 1] - x;
        }
        if (a[i + 1] < 0)
        a[i + 1] = 0;
    }
    printf("%lld",sum);
    
    return 0;
}

P3818 小A和uim之大逃离 II

    • 164通过
    • 814提交
  • 题目提供者lzn
  • 标签
  • 难度普及+/提高
  • 时空限制1s / 128MB

 提交  讨论  题解  

最新讨论更多讨论

  • 求第二个点数据
  • lunch点进来
  • 20分求助
  • 放弃!80分求差错wa第二个第…
  • 题目数据范围有误
  • 为什么第七个点会RE

题目背景

话说上回……还是参见 https://www.luogu.org/problem/show?pid=1373 吧

小a和uim再次来到雨林中探险。突然一阵南风吹来,一片乌云从南部天边急涌过来,还伴着一道道闪电,一阵阵雷声。刹那间,狂风大作,乌云布满了天空,紧接着豆大的雨点从天空中打落下来,只见前方出现了一个牛头马面的怪物,低沉着声音说:“呵呵,既然你们来到这,两个都别活了!”。小a和他的小伙伴再次惊呆了!

题目描述

瞬间,地面上出现了一个H行W列的巨幅矩阵,矩阵的每个格子上要么是空地‘.’或者障碍'#'。

他们起点在(1,1),要逃往(H,W)的出口。他们可以一次向上下左右移动一格,这个算一步操作。不过他们还保留着上次冒险时收集的魔液,一口气喝掉后可以瞬移到相对自己位置的(D,R)向量;也就是说,原来的位置是(x,y),然后新的位置是(x+D,y+R),这个也算一步操作,不过他们仅能至多进行一次这种操作(当然可以不喝魔液)。

这个地方是个是非之地。所以他们希望知道最小能有几步操作可以离开这个鬼地方。不过他们可能逃不出这个鬼地方,遇到这种情况,只能等死,别无他法。

输入输出格式

输入格式:

 

第一行个整数,H W D R,意义在描述已经说明。

接下来H行,每行长度是W,仅有'.'或者'#'的字符串。

 

输出格式:

 

请输出一个整数表示最小的逃出操作次数。如果他们逃不出来,就输出-1。

 

输入输出样例

输入样例#1:
3 6 2 1
...#..
..##..
..#...
输出样例#1:
5
输入样例#2:
3 7 2 1
..#..#.
.##.##.
.#..#..
输出样例#2:
-1
输入样例#3:
6 6 -2 0
.#....
.#.#..
.####.
.#..#.
.##.#.
....#.
输出样例#3:
21

说明

样例解释1

(1,1)→(1,2)→(1,3)→喝(3,4)→(3,5)→(3,6)

样例解释2

因为只有一瓶魔液所以他们没办法逃出来

样例解释3

D和R还可以是0或者负数。

数据范围与约定

40%的测试数据2<=H,W<=5

70%的测试数据2<=H,W<=100

100%的测试数据2<=H,W<=1000,|D|<H,|R|<W

分析:其实这是一道比较简单的bfs的题,如果是求最短路,一次bfs即可,如果加上魔液,其实也非常简单,只需要加一维来表示喝不喝魔液即可.

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <string>

using namespace std;

int h, w, d, r,map[1010][1010],vis[1010][1010][2],ans;
char ss[1010][1010];
int dx[4] = { 0, 1, 0, -1 }, dy[4] = { 1, 0, -1, 0 };
string s[1010];

struct node
{
    int dist, use, x, y;
};

int bfs()
{
    queue <node> q;
    node a;
    a.dist = 0;
    a.use = 0;
    a.x = 1;
    a.y = 1;
    q.push(a);
    vis[1][1][0] = 1;
    while (!q.empty())
    {
        node t = q.front();
        q.pop();
        if (t.x == h && t.y == w)
            return t.dist;
        for (int i = 0; i < 4; i++)
        {
            int nx = t.x + dx[i], ny = t.y + dy[i];
            if (nx > 0 && nx <= h && ny > 0 && ny <= w && !vis[nx][ny][t.use] && map[nx][ny] != 1)
            {
                vis[nx][ny][t.use] = 1;
                node temp;
                temp.x = nx, temp.y = ny, temp.use = t.use, temp.dist = t.dist + 1;
                q.push(temp);
            }
        }
        if (t.use == 0)
        {
            int nx = t.x + d, ny = t.y + r;
            if (nx > 0 && nx <= h && ny > 0 && ny <= w && !vis[nx][ny][1] && map[nx][ny] != 1)
            {
                vis[nx][ny][1] = 1;
                node temp;
                temp.x = nx, temp.y = ny, temp.use = 1, temp.dist = t.dist + 1;
                q.push(temp);
            }
        }
    }
    return -1;
}

int main()
{
    scanf("%d%d%d%d", &h, &w, &d, &r);
    for (int i = 0; i < h; i++)
        cin >> s[i];
    for (int i = 1; i <= h; i++)
        for (int j = 1; j <= w; j++)
        {
        if (s[i-1][j-1] == '#')
            map[i][j] = 1;
        else
            map[i][j] = 0;
        }
    ans = bfs();
    printf("%d\n", ans);

    return 0;
}

P3819 松江1843路

    • 151通过
    • 580提交
  • 题目提供者lin_toto
  • 标签
  • 难度普及+/提高
  • 时空限制1s / 128MB

 提交  讨论  题解  

最新讨论更多讨论

题目描述

涞坊路是一条长L米的道路,道路上的坐标范围从0到L,路上有N座房子,第i座房子建在坐标为x[i]的地方,其中住了r[i]人。

松江1843路公交车要在这条路上建一个公交站,市政府希望让最多的人得到方便,因此希望所有的每一个的居民,从家到车站的距离的总和最短。

公交站应该建在哪里呢?

输入输出格式

输入格式:

 

第一行输入L、N。

接下来N行,每行两个整数x[i]和r[i]。

 

输出格式:

 

一个整数,最小的每个人从家到车站的距离的总和。

 

输入输出样例

输入样例#1:
100 3
20 3
50 2
70 1
输出样例#1:
110

输入样例#2:
100 2
0 1
100 10
输出样例#2:
100
输入样例#3:
10000000000 5
3282894320 391
4394338332 929
6932893249 181
7823822843 440
9322388365 623
输出样例#3:
5473201404068

说明

样例解释1

当建在坐标40的时候,所有人距离车站的距离总和为 |20−40|×3+|50−40|×2+|70−40|×1=110。

数据范围和约定

对于10%的数据,1≤N≤50,R[i]=1。

对于30%的数据,1≤N≤100,R[i]≤10,1≤L≤1000。

对于70%的数据,1≤N≤1000,R[i]≤100,1≤L≤10^6。

对于全部数据,1≤L≤10^10,1≤N≤10^5,0≤x[i]≤L,1≤r[i]≤1000

分析:根据小学奥数,我们可以知道车站一定建在中位数上,那么我们只需要求出中位数是多少即可。至于求中位数就很简单了,只需要算出中位数是哪一个人,在读入的时候就可以顺便完成了.

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

long long L, n,tot,sum,ans,cnt;

struct node
{
    long long x,r;
}e[100010];

bool cmp(node a, node b)
{
    return a.x < b.x;
}

int main()
{
    scanf("%lld%lld", &L, &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld%lld", &e[i].x, &e[i].r);
        tot += e[i].r;
    }
    tot = (tot + 1) / 2;
    sort(e + 1, e + 1 + n, cmp);
    for (int i = 1; i <= n; i++)
    {
        sum += e[i].r;
        if (sum >= tot)
        {
            cnt = e[i].x;
            break;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        ans += abs((e[i].x - cnt)) * e[i].r;
    }
    printf("%lld", ans);

    return 0;
}

P3820 小D的地下温泉

    • 48通过
    • 620提交
  • 题目提供者zhouyonglong
  • 标签洛谷原创
  • 难度提高+/省选-
  • 时空限制1s / 128MB

 提交  讨论  题解  

最新讨论更多讨论

  • 求大佬改错,总是50分,我真…
  • 求大佬改错,只对了1,2,10点…
  • 蜜汁CE
  • 有人有数据吗

题目背景

小D最喜欢泡温泉了。小D找某奸商租下了一块列的地,左上角为,右下角为。小D本以为这块地里全是温泉,结果这块地极不稳定,曾经发生过一些地形变动,所以其中一些地方全是土。

题目描述

一开始他会告诉你当前这块地的情况,但是小D有一些假操作,希望你操作给他看:

  1. 由小D指定个位置,他希望知道其中哪个位置下水泡温泉的范围最大。泡温泉的范围定义为指定位置通过向上下左右四个方向能到达的位置的个数。若询问的位置为土,则范围为0。如果如果有多个位置均为最大,输出给出顺序较前的那个。位置编号为

  2. 由小D指定个位置,他会使用膜法按顺序翻转这个地方的地形。即若原位置是土,则该位置变为温泉;若原位置是温泉,则该位置变为土。因为小D不希望活动范围减少得太快,所以他在将温泉变为土时不会将一个区域分割。

输入输出格式

输入格式:

 

第一行输入两个整数,,为土地大小。

接下来的行每行输入个字符,为'.'(代表温泉)或'*'(代表土)(不包括引号)

行输入一个整数,,为操作数量。

接下来的行,每行先读入两个整数,表示操作类型和指定点的数量,在同一行还有个数,分别表示个操作的位置为

 

输出格式:

 

对于每个操作1,输出询问的答案并换行

 

输入输出样例

输入样例#1:
5 5
.*...
.****
*....
*****
.....
3
1 2 1 1 1 3
2 1 3 1
1 2 1 1 1 3
输出样例#1:
2
1

说明

对于30%的数据,

对于70%的数据,

对于100%的数据,

数据在windows下制作

分析:第一想法当然是对于每个询问都暴力咯,但是可以优化,我们其实不需要在每次询问时都做一次dfs,可以将连通块看作一个整体,这可以用到并查集,

用一个数组保存每个连通块的大小,对于每个询问1,直接找即可,对于询问2,如果把温泉变做土,则所属连通块的大小-1,这个点不属于任何连通块,如果

把土变成温泉,则将这个点与周围4个连通块合并一下即可。不过巨坑的一点是数据范围是n*m <= 10^6,所以要把数组开成一维数组,方法就是给每个点标号,

根据标号来操作即可.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>

using namespace std;

int n, m,map[1010000],vis[1010000],top,num[1111000],faa[1010000],q,fa[1010001];
char c;

void dfs(int x, int y)
{
    int id = (x - 1) * m + y;
    vis[id] = 1;
    if (map[id] == 1)
        return;
    fa[id] = top;
    num[top]++;
    if (x + 1 <= n && !vis[x * m + y])
        dfs(x + 1, y);
    if (y + 1 <= m && !vis[(x - 1) * m + y + 1])
        dfs(x, y + 1);
    if (x - 1 > 0 && !vis[(x - 2) * m + y])
        dfs(x - 1, y);
    if (y - 1 > 0 && !vis[(x - 1) * m + y - 1])
        dfs(x, y - 1);
}

int find(int x)
{
    if (faa[x] == x)
        return x;
    return faa[x] = find(faa[x]);
}

void hebing(int a, int b, int a2, int b2)
{
    int id1 = (a - 1) * m + b, id2 = (a2 - 1) * m + b2;
    int f1 = find(fa[id1]), f2 = find(fa[id2]);
    if (map[id1] == 1 || map[id2] == 1 || f1 == f2)
        return;
    num[f1] += num[f2];
    num[f2] = 0;
    faa[f2] = f1;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
        {
            int id = (i - 1) * m + j;
            c = getchar();
            while (c != '.' && c != '*')
                c = getchar();
            if (c == '.')
                map[id] = 0;
            else
                map[id] = 1;
        }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
        {
            int id = (i - 1) * m + j;
            if (!vis[id] && map[id] == 0)
            {
                ++top;
                dfs(i, j);
            }
        }
    for (int i = 1; i <= top; i++)
        faa[i] = i;
    scanf("%d", &q);
    for (int i = 1; i <= q; i++)
    {
        int opt, w;
        scanf("%d%d", &opt, &w);
        if (opt == 1)
        {
            int ans = 0,ans2 = 1;
            for (int i = 1; i <= w; i++)
            {
                int x, y;
                scanf("%d%d", &x, &y);
                int id = (x - 1) * m + y;
                if (map[id] == 1)
                    continue;
                int f = find(fa[id]);
                if (num[f] > ans)
                {
                    ans = num[f];
                    ans2 = i;
                }
            }
            printf("%d\n", ans2);
        }
        else
        {
            for (int i = 1; i <= w; i++)
            {
                int x, y;
                scanf("%d%d", &x, &y);
                int id = (x - 1) * m + y;
                if (map[id] == 0)
                {
                    map[id] = 1;
                    int f = find(fa[id]);
                    num[f]--;
                    fa[id] = 0;
                }
                else
                {
                    map[id] = 0;
                    top++;
                    fa[id] = top;
                    faa[top] = top;
                    num[top]++;
                    if (x + 1 <= n)
                    hebing(x, y, x + 1, y);
                    if (x - 1 >= 1)
                    hebing(x, y, x - 1, y);
                    if (y + 1 <= m)
                    hebing(x, y, x, y + 1);
                    if (y - 1 >= 1)
                    hebing(x, y, x, y - 1);
                }
            }
        }
    }

    return 0;
}

 

转载于:https://www.cnblogs.com/zbtrs/p/7235873.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值