谷仓

谷仓

编程社四连测

目录

目录

谷仓

编程社四连测

目录

题目

样例输入

样例输出

解析

代码(一)

代码(二)


题目

题目描述

有一个圆形的谷仓,共有n个房间,按顺时针编号从1到n。现在有许多头奶牛,他们都有自己最喜欢的一个房间。傍晚回家时,奶牛们去找自己最喜欢的房间。如果发现被占了,他们就会按照顺时针方向找第一个空闲的房间住进去。现在请你输出最小的空闲的房间号。注意,这个答案和奶牛们回家的顺序是无关的。

2<=n<=3000000,1<=k<=10000,A,B的值在区间[0,10^9]。

输入

输入格式:

第一行两个整数n,k。

接下来有k行。每行4个整数,x,y,a,b.表示有x头奶牛喜欢f[1],f[2]……,f[y]。其中f[i]=(a*i+b)%n+1.

输出

输出最小的空闲房间号。

样例输入

10 3
3 2 2 4
2 1 0 1
1 1 1 7

样例输出

6

解析

此题其实我们可以使用暴搜的思想解决,我们首先循环一遍,将有奶牛喜欢的房间都放一头奶牛,我们以样例为例:

1 2 3 4 5 6 7 8 9 10
0 2 0 0 0 0 4 0 3 0

我们首先把数据读进了 a 数组里,然而我们还需要一个变量  sum ,存放后还剩的奶牛个数

i sum a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] a[10]
1 0 0 2 0 0 0 0 4 0 3 0
2 1 0 1 0 0 0 0 4 0 3 0
3 0 0 1 1 0 0 0 4 0 3 0
4 0 0 1 1 0 0 0 4 0 3 0
5 0 0 1 1 0 0 0 4 0 3 0
6 0 0 1 1 0 0 0 4 0 3 0
7 3 0 1 1 0 0 0 1 0 3 0
8 2 0 1 1 0 0 0 1 1 3 0
9 4 0 1 1 0 0 0 1 1 1 0
10 3 0 1 1 0 0 0 1 1 1 1

最后我们发现只剩下 3 只奶牛未能进仓,所以我们还需要二次遍历,仍然是从头开始,将剩余牛一次放入未有奶牛的谷仓(因为最后几个位置一定是被占满的,否则就不会多出奶牛,奶牛要么是前面谷仓多出的牛,它们有仓就进最后未能进谷仓的一定是多出的奶牛,其次就是最后一个谷仓的奶牛,它们从下一个位置顺时针遍历就是从 1 号元素开始)

i sum a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] a[10]
0 3 0 1 1 0 0 0 1 1 1 1
1 2 1 1 1 0 0 0 1 1 1 1
2 2 1 1 1 0 0 0 1 1 1 1
3 2 1 1 1 0 0 0 1 1 1 1
4 1 1 1 1 1 0 0 1 1 1 1
5 0 1 1 1 1 1 0 1 1 1 1
6 0 1 1 1 1 1 0 1 1 1 1
7 0 1 1 1 1 1 0 1 1 1 1
8 0 1 1 1 1 1 0 1 1 1 1
9 0 1 1 1 1 1 0 1 1 1 1
10 0 1 1 1 1 1 0 1 1 1 1

至此,大概的算法已经明白,所以就直接看代码吧

代码(一)

#include<cstdio>
#define M 3000000 + 5
#define LL long long
#define reg register

LL sum,n,k;
LL a[M];

int main(){
    scanf("%lld%lld",&n,&k);
    for (reg int i = 1;i <= k; ++ i){
        int x,y;
        LL a1,b;
        scanf("%d%d%lld%lld",&x,&y,&a1,&b);
        for (reg int j = 1;j <= y; ++ j){
            int s = (a1 * j + b) % n + 1;
            a[s] += x;
        }
    }
    for (reg int i = 1;i <= n; ++ i){
        if (sum || a[i]){
            sum += (a[i] - 1);
            a[i] = 1;
        }
    }
    int i = 1;
    while (i <= n){
        if (sum || a[i]){
            sum += a[i] - 1;
            a[i] = 1;
        }
        if ( ! sum && ! a[i]){
            printf("%d\n",i);
            return 0;
        }
        ++ i;
    }
    return 0;
}

想必这里大家会有个疑惑吧

if (sum || a[i]){
     sum += (a[i] - 1);
     a[i] = 1;
}

其实这里很好明白,再次运用我们分类讨论的方法:

  1. sum != 0 && a[i] != 0,我们就可以把a[i] - 1 只奶牛放入 sum 里
  2. sum == 0 && a[i] != 0 ,同上
  3. sum != 0 && a[i] == 0,因为这里是 sum += (a[i] - 1);,所以加一个负数就等于减去那个数的相反数,如果 a[i] == 1 的话,其实就相当于不对他就行操作
  4. sum == 0 && a[i] == 0,完全进不去,既然没有多余的牛,谷仓里也没有牛,我们操作干嘛呢

但是这份代码,大家尽量不要尝试,原因有下:

  1. (错得有点多)

  2. 我们再对比一下,即将给出代码的时间(一),和这份代码的时间(二)

一)

二)

代码(二)

其实就是将第一个代码中的 while 变为 for 循环,然后再用一个 for 循环找答案 (这个竟然要快一些,可能是因为 for 比 while 节时一些吧)

#include<cstdio>
#define M 3000000 + 5
#define LL long long
#define reg register
 
LL sum,n,k;
LL a[M];
 
int main(){
    scanf("%lld%lld",&n,&k);
    for (reg int i = 1;i <= k; ++ i){
        int x,y;
        LL a1,b;
        scanf("%d%d%lld%lld",&x,&y,&a1,&b);
        for (reg int j = 1;j <= y; ++ j){
            int s = (a1 * j + b) % n + 1;
            a[s] += x;
        }
    }
    for (reg int i = 1;i <= n; ++ i){
        if (sum || a[i]){
            sum += (a[i] - 1);
            a[i] = 1;
        }
    }
    for (reg int i = 1;i <= n; ++ i){
        if (sum || a[i]){
            sum += (a[i] - 1);
            a[i] = 1;
        }
    }
    for (reg int i = 1;i <= n; ++ i){
        if ( ! a[i]){
            printf("%d",i);
            return 0;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_43904786/article/details/85337454
今日推荐