题目大意:
有一个圆形的谷仓,共有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
重难点思想:
首先先要理解到这道题的意思,是说每一行喜欢f[i]的房间都有x头奶牛,理解到这一步后,就可以从无从下手到RE。
再来分析,由于我们的a ,b 很大,所以有可能会爆long long , 即使这里有余数还是会爆,故,我们要模三次:
int js( int i ){
long long sum =( ( i * s ) % n + b % n ) % n;
int k = sum % n;
return k + 1;
}
然后就可以从RE晋升到TLE……
我们现在来优化模拟的方法:
用最简单的贪心来想,我们只让第i个房间保留1头奶牛,其余的全都移到下一个房间中,这样虽然一遍解决不了,但是跑2*n就可以把所有牛都放进去,最后再找空余的即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int n , m;
long long s , b , x , y;
long long a[3000003];
int js( int i ){
long long sum =( ( i * s ) % n + b % n ) % n;
int k = sum % n;
return k + 1;
}
void read( long long &x ){
int f = 1; x = 0;
char s = getchar();
while( s < '0' || s > '9' ){
if( s == '-' )
f = -1;
s = getchar();
}
while( s >= '0' && s <= '9' ){
x = x * 10 + s - '0';
s = getchar();
}
x *= f;
}
int main(){
scanf( "%d%d" , &n , &m );
for( int i = 1 ; i <= m ; i ++ ){
read( x );
read( y );read( s );read( b );
for( int j = 1 ; j <= y ; j ++ )
a[js( j )] += x;
}
for( int j = 1 ; j <= 3 ; j++ ){
for( int i = 1 ; i <= n ; i ++ ){
if( a[i] > 1 ){
if( i == n )
a[1] += a[n] - 1;
else
a[ i + 1 ] += a[i] - 1;
a[i] = 1;
}
}
}
for( int i = 1 ; i <= n ; i ++ )
if( a[i] == 0 ){
printf( "%d" , i );
return 0;
}
return 0;
}