没有原题
似乎来自某校模拟赛….
Description
热爱看书的你有N本书, 第i本书的种类为A[i]. 你希望每天能够看一本书, 但是不希望连续两天看种类相同的书. 为了达成这个条件, 你需要选择一些书不看, 作为一个好学生, 你希望不看的书尽可能少, 求最少可以有多少书不看.
Input
为了避免输入文件过大, 我们采取如下方式生成A[i].
第一行读入两个个整数M, K.
接下来一行读入M个整数count[i], 其中N=∑count [i].
接下来一行读入M个整数X[i].
接下来一行读入M个整数Y[i].
接下来一行读入M个整数Z[i].
然后按照下面这段代码生成.
int N = 0, S = (1 << K) - 1;
for (int i = 1; i <= M; ++i) {
N = N + 1;
A[N] = X[i];
long long last = X[i];
for (int j = 1; j < count[i]; ++j) {
last = (last * Y[i] + Z[i]) & S;
N = N + 1;
A[N] = last;
}
}
注意:因为生成A[i]的方法不好用语言描述, 所以用代码来表达. 直接照搬代码的话后果自负.
Output
输出一个整数表示答案.
Sample Input
4 2
1 1 1 1
1 1 1 2
0 0 0 0
0 0 0 0
Sample Output
1
Hint
对于所有数据, N <= 50000000, M <= 1000, K <= 30, X[i], Y[i] < 2^k.
subtask#1 10pts: N <= 20.
subtask#2 20pts : N <= 1000000.
subtask#3 20pts: K <= 20.
subtask#4 50pts: 无特殊限制.
Solution
- 由于N过大,这是一个强制在线的算法。
可以皮一下照搬生成代码 - 来考虑数量最多的一种书,如果≤(n+1)/2,那一定可以全部读完,反之就需要舍弃
- 如何在不能记下a[i]的状况下进行判断?可以把书类似两两配对的来处理
- now记录当前找到重复的书,num记录个数,遇到相同的num+1,不同则num-1。如果生成一个类别时num=0,那么将now更新成a[i],num更新为1
- 如果没有数量≥(n+1)/2的书,最后num一定等于零
- 对于有数量≥(n+1)/2的书的情况,再做一遍找出now的具体个数,简单计算即可
当时想了很久没记下a[i]怎么再做一遍
Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define ll long long
int m,k,x[1007],y[1007],z[1007],count[1007],a[1007];
int num,now,H;
int read(){
int x=0,f=1;
char ch=getchar();
while (!(ch>='0'&&ch<='9')){if (ch=='-') f=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main(){
m=read(); k=read();
for (int i=1;i<=m;i++) count[i]=read();
for (int i=1;i<=m;i++) x[i]=read();
for (int i=1;i<=m;i++) y[i]=read();
for (int i=1;i<=m;i++) z[i]=read();
int n=0,s=(1<<k)-1;
for (int i=1;i<=m;i++){
n++;
H=x[i];
if (num==0){now=H; num=1;}
else if (now==H) num++; else num--;
//printf("%d ",H);
ll last=x[i];
for (int j=1;j<count[i];j++){
last=(last*y[i]+z[i])&s;
n++;
H=last;
if (num==0){now=H; num=1;}
else if (now==H) num++; else num--;
}
}
n=0,s=(1<<k)-1; num=0;
for (int i=1;i<=m;i++){
n++;
H=x[i];
if (H==now) num++;
ll last=x[i];
for (int j=1;j<count[i];j++){
last=(last*y[i]+z[i])&s;
n++;
H=last;
if (H==now) num++;
}
}
if (num>((n+1)/2)) printf("%d\n",num-(n-num)-1);
else printf("0\n");
return 0;
}