您的位置:首页 > 其它

2017洛谷7月月赛总结

2017-07-25 18:47 204 查看

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

提交 讨论 题解

最新讨论更多讨论

暴力70分,如何优化?

这里就没有写三分的吗?

题目描述

涞坊路是一条长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 53282894320 391
4394338332 929
6932893249 181
7823822843 4409322388365 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有一些假操作,希望你操作给他看:

由小D指定

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



由小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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: