问题 I: Slot Machine()KMP找最小循环节)

本文探讨了一种利用老虎机伪随机数生成器周期性缺陷的方法,通过分析连续的老虎机结果序列,找出最小的k和p值,使后续结果可预测,从而揭示了现代老虎机可能存在的安全漏洞。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

9318: Slot Machines

时间限制: 1 Sec  内存限制: 128 MB
提交: 191  解决: 49
[提交] [状态] [讨论版] [命题人:admin]

题目描述

Slot machines are popular game machines in casinos. The slot machine we are considering has six places where a figure appears. By combination of figures, one may earn or lose money. There are ten kinds of figures, so we will represent a figure with a number between 0 and 9. Then we can use a six-digit number w = w1w2w3w4w5w6 where 0 ≤ w1, w2, w3, w4, w5, w6 ≤ 9 to represent one possible outcome of the slot machine.

Figure I.1. The layout of a slot machine.


Old slot machines were made up with mechanical components, but nowadays they were replaced by PC-based systems. This change made one critical flaw: they are based on pseudo-random number generators and the outcome sequences of a slot machine are periodic. Let T[i] be the i-th outcome of a slot machine. At first, there is a truly random sequence of length k,T[1],T[2],…,T[k]. Then there exists one positive number such that T[i+p] = T[i]for all possible values of i(>k). Once an attacker can find out the exact values of k and p, he or she can exploit this fact to beat the casino by betting a lot of money when he or she knows the outcome with a good combination in advance.

For example, you have first six numbers of outcome sequences: 612534, 3157, 423, 3157, 423, and 3157. Note that we can remove first 0’s. Therefore, 3157 represents 003157 and 423 represents 000423. You want to know its tenth number. If you know the exact values of k and p, then you can predict the tenth number. However, there are many candidates for k and p: one extreme case is k=5 and p=1, and another is k=0 and p=6. The most probable candidate is the one where both k and p are small. So, our choice is the one with the smallest k+p. If there are two or more such pairs, we pick the one where p is the smallest. With our example, after some tedious computation, we get k=1 and p=2.

Assume that you have n consecutive outcomes of a slot machine, T[1], T[2], …, T[n]. Write a program to compute the values of k and p satisfying the above-mentioned condition.

 

输入

Your program is to read from standard input. The first line contains a positive integer n (1 ≤ n ≤ 1,000,000), representing the length of numbers we have observed up to now in the outcome sequence. The following line contains n numbers. Each of these numbers is between zero and 999,999.

 

输出

Your program is to write to standard output. Print two integers k and p in one line.

 

样例输入

6
612534 3157 423 3157 423 3157

 

样例输出

1 2

 

来源/分类

ICPC 2017 Daejeon 

 

题意:数组a有n个数字,数字范围0~999999希望求一组最小的k+p,使得任意i>k,都有a[i]=a[i+p],若两组k+p大小相等,取p较小的

思路:p为循环节,也就是说要求最小的周期。将a序列倒序,求出next数组,用前n的长度减去next数组里的n-1就是最小循环节的长度。

#include<bits/stdc++.h>
using namespace std;
int te[1000005];
int t[1000005];
int nextnum[1000010];
int main()
{
        int step=1,n;
        scanf("%d",&n);
        for(int i = 0;i < n;i++)
        {
            scanf("%d",te+i);
        }
        for(int i = n-1;i >= 0;i--)
        {
            t[n-i-1] = te[i];
        }
        //cout<<s<<endl;
        int len=n;
        int i=0,j=1;
        while(j<len)  //先写出next数组
        {
            if(t[i]!=t[j]&&i!=0)
            {
                i=nextnum[i-1];
            }
            else if(t[i]!=t[j]&&i==0)
            {
                nextnum[j]=0;
                j++;
            }
            else if(t[i]==t[j])
            {
                nextnum[j]=i+1;
                j++,i++;
            }
        }
        int k = 9999999,p = 999999;
        for(int i = 1;i <= n;i++)
        {
            int pp=i-nextnum[i-1];
            if(pp + (n-i) < (k+p))
            {
                k = n-i;
                p = pp;
            }
            if(pp + (n-i) == (k+p))
            {
                if(pp < p)
                {
                    k = n-i;
                    p = pp;
                }
            }
        }
 
        printf("%d %d",k,p);
        printf("\n");
    return 0;
}

 

KMP算法的核心在于构建部分匹配表(也称为`next`数组),该表用于记录模式串的部分匹配信息。通过这些信息,可以在寻重复子串的过程中优化查效率。 要利用KMP算法来出字符串的最小循环节,可以通过以下方法实现: ### 使用 KMP 最小循环节 对于一个长度为 `n` 的字符串 `s`,如果存在某个最小子串 `p` 能够通过多次复制构成原字符串,则这个子串即是最小循环节。以下是具体过程: #### 构建 Next 数组 定义一个辅助函数计算前缀函数值并存储于 next 数组中。此操作的时间复杂度为 O(n)[^1]。 ```python def compute_next_array(pattern): n = len(pattern) next_arr = [0] * n j = 0 for i in range(1, n): while j > 0 and pattern[i] != pattern[j]: j = next_arr[j - 1] if pattern[i] == pattern[j]: j += 1 next_arr[i] = j return next_arr ``` #### 计算最小循环节 基于上述得到的 next 数组,我们可以进一步推导出最小周期 t=n&minus;next[n&minus;1] 。当满足条件 (t 可整除 n),则表明 s 存在一个大小为 t 的基本单元反复拼接而成;否则整个字符串本身不具备更短的有效循环结构。 ```python def find_smallest_repeating_substring(s): next_arr = compute_next_array(s) length_of_string = len(s) period = length_of_string - next_arr[-1] if length_of_string % period == 0 and period != length_of_string: return s[:period] else: return s ``` 以上代码片段展示了如何应用 KMP 中的 next 数组特性去检测是否存在以及返回目标字符串内的最简重复序列。 ### 结论 综上所述,借助 KMP 算法不仅可以高效解决模式匹配问题,在特定场景下还能巧妙运用于诸如发现字符串内部隐藏规律的任务之中,比如本例中的定位最小循环单位即是如此。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值