ACM-ICPC Northeastern European Regional Contest (NEERC 15) -Generators

Little Roman is studying linear congruential generators -- one of the oldest and best known pseudorandom number generator algorithms. Linear congruential generator (LCG) starts with a non-negative integer number 0x0​ also known as seed and produces an infinite sequence of non-negative integer numbersxi​(0≤xi​

xi+1​=(axi​+b) mod c

here a , b , and c are non-negative integer numbers and 0≤x0​

Roman is curious about relations between sequences generated by different LCGs. In particular, he has n different LCGs with parameters a(j),b(j), and c(j) for 1≤j≤n , where the j-th LCG is generating a sequence xi(j)​. He wants to pick one number from each of the sequences generated by each LCG so that the sum of the numbers is the maximum one, but is not divisible by the given integer number k .

Formally, Roman wants to find integer numberstj​≥0 for1≤j≤n to maximize s=Σj=1n​xtj​(j)​ subject to constraint that s mod.

输入格式

The first line of the input file contains two integer numbers �n and �(1≤�≤10000,1≤�≤109).k(1≤n≤10000,1≤k≤109). The following �n lines describe LCGs. Each line contains four integer numbers �0(�),�(�),�(�),x0(j)​,a(j),b(j), and �(�)(0≤�(�),�(�)≤1000,0≤�0(�) <�(�)≤1000)c(j)(0≤a(j),b(j)≤1000,0≤x0(j)​ 

输出格式

If Roman's problem has a solution, then write on the first line of the output file a single integer �s -- the maximum sum not divisible by �k , followed on the next line by �n integer numbers ��(0≤��≤109)tj​(0≤tj​≤109) specifying some solution with this sum.

Otherwise, write to the output file a single line with the number −1−1 .

题意翻译

题目描述

罗曼在学习线性同余发生器——最古老,也是最广为人知的伪随机数生成算法之一。线性同余发生器(LCG)以 �0x0​ 为随机种子,生成很多非负整数 ��xi​ ,它遵循以下规则:

给定非负整数 �,�,� (0≤�0<�)a,b,c (0≤x0​

罗曼很好奇由不同LCG产生的序列之间的关系。特别地,他有 �n 个不同的LCG,含有参数 �(�),�(�),�(�) (1≤�≤�)a(j),b(j),c(j) (1≤j≤n)。第 �j 个LCG会生成一个序列 ��(�)xi(j)​ 。

他希望能从每个LCG产生的序列中挑出一个数,使他们的和最大,且不被给定的 �k 整除。

格式化一点来说,他希望找到整数 �� (��>0,1≤�≤�)tj​ (tj​>0,1≤j≤n) ,使�=∑�=1����(�)s=j=1∑n​xtj​(j)​最大,且�≢0(��� �)s≡0(mod k)。

输入格式

第 11 行包括两个整数�,�n,k。

(1≤�≤10000,1≤�≤109)(1≤n≤10000,1≤k≤109)

接下来 �n 行描述LCG,每行包括4个整数:�0(�),�(�),�(�),�(�)x0(j)​,a(j),b(j),c(j) 。

(0≤�(�),�(�)≤1000,0≤�0(�)<�(�)≤1000)(0≤a(j),b(j)≤1000,0≤x0(j)​

输出格式

如果有解,第 11 行输出 �s,第 22 行输出 �n 个 ��tj​ 。

(0≤��≤109)(0≤tj​≤109) 。

如果无解,输出 −1−1 。

说明/提示

时间限制:1秒

空间限制:256MB

输入输出样例

输入 #1复制

2 3
1 1 1 6
2 4 0 5

输出 #1复制

8
4 1

输入 #2复制

2 2
0 7 2 8
2 5 0 6

输出 #2复制

-1

 思路:

In the first example, one LCG is generating a sequence 1, 2, 3, 4, 5, 0, 1, 2, . . ., while the other LCG a sequence 2, 3, 2, 3, 2, . . ..

In the second example, one LCG is generating a sequence 0, 2, 0, 2, 0, . . ., while the other LCG a sequence 2, 4, 2, 4, 2, . . ..

看例子,对于每个例子,它的取余数列差是一定的,1,2,3,4,5和2,3,2,3,和2,4,2,4;

(sum-cha[i])%k=(sum%k-cha[i]%k)%k,如果cha[i]%k==0,那(sum-cha[i])%k==0;

所以我们只需要记录每一个数列的最大值和次大值和他们的位置。

如果n个最大值之和%k!=0,直接输出最大值和他们位置。

如果存在(sum-a[1]+a[2])%k!=0,找到最大的sum-a[1]+a[2];

如果都不存在,输出-1;

对于每一个数列:我们只需要循环c+1次,因为对c取余最多有(0,c-1)个值,我们循环c+1次,一定可以取到能取到的所有值,一旦遇到以前出现过的值,就不再往下计算(因为会进入循环)。

记录每一个数列的最大值和次大值和他们的位置。

代码:

#define _CRT_SECURE_NO_WARNINGS 
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const long long N = 1e4 + 1000;
const long long MAX = 1e9;
#define per(i,a,b) for(int i=a;i<=b;i++)
#define der(i,a,b) for(int i=a;i>=b;i--)
#define LL long long 
LL sum = 0;
int pos[N][3], ma[N][3], n, k, vis[1100], cnt;
int main()
{  
    freopen("generators.in", "r", stdin);
   freopen("generators.out", "w", stdout);
    int a, b, c, x;
    cin >> n >> k;
    memset(ma,0 ,sizeof ma);
    memset(pos, 0, sizeof pos);
    per(i, 1, n)
    {
        scanf("%d%d%d%d", &x, &a, &b, &c);
        memset(vis, 0, sizeof vis);
        ma[i][1] = ma[i][2] = 0;
        pos[i][1] = pos[i][2] = 0;
        vis[x] = 1;
        cnt = 0;
        per(j, 0, c + 10)
        {
            if (x > ma[i][1])
            {
                ma[i][2] = ma[i][1];
                pos[i][2] = pos[i][1];
                ma[i][1] = x;
                pos[i][1] = j;
            }
            else if (x > ma[i][2])
            {
                ma[i][2] = x;
                pos[i][2] = j;
            }
            x = (a * x + b) % c;
            if (vis[x]) break;
            vis[x] = 1;
            cnt++;
        }
        if (cnt == 0)
        {
            ma[i][1] = ma[i][2] = x;
            pos[i][1] = pos[i][2] = 0;
        }
        sum += ma[i][1];
    }
    if (sum % k)
    {
        printf("%lld\n", sum);
        per(i, 1, n)
            printf("%d ", pos[i][1]);
        printf("\n");
    }
    else
    {
        LL y = 0, tmp = -1;
        per(i, 1, n)
        {
            if ((sum - ma[i][1] + ma[i][2]) % k && sum - ma[i][1] + ma[i][2] > tmp)
            {
                tmp = sum - ma[i][1] + ma[i][2];
                y = i;
            }
        }
        if (tmp == -1 || tmp % k == 0)
            printf("-1\n");
        else
        {
            printf("%lld\n", tmp);
            per(i, 1, n)
            {
                if (y != i)
                    printf("%d ", pos[i][1]);
                else
                    printf("%d ", pos[i][2]);
            }
            printf("\n");
        }
    }
    return 0;
}

你可能感兴趣的:(数论,算法)