YBT-开关灯(t1109)

描述

假设有N盏灯(N为不大于5000的正整数),从1到N按顺序依次编号,初始时全部处于开启状态;有M个人(M为不大于N的正整数)也从1到M依次编号。

第一个人(1号)将灯全部关闭,第二个人(2号)将编号为2的倍数的灯打开,第三个人(3号)将编号为3的倍数的灯做相反处理(即将打开的灯关闭,将关闭的灯打开)。依照编号递增顺序,以后的人都和3号一样,将凡是自己编号倍数的灯做相反处理。

请问:当第M个人操作之后,哪几盏灯是关闭的,按从小到大输出其编号,其间用逗号间隔。

输入描述

输入正整数N和M,以单个空格隔开。

输出描述

顺次输出关闭的灯的编号,其间用逗号间隔。

用例输入 1 

10 10

用例输出 1 

1,4,9
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,m;
	cin>>n>>m;
	int light[n];
    for(int i=0;i<n;i++)
    {
        light[i]=1;
    }
	for(int i=1;i<=m;i++)
	{
		for(int j=i-1;j<n;j=j+i)
		{
         
                light[j]=!(light[j]);
            //cout<<j<<" "<<light[j]<<"   ";
		}	
        //cout<<endl;
	}
    int a=0;
    for(int i=0;i<=n;i++)
    {
        //cout<<light[i]<<" ";
        
        if(light[i]==0)
        {
            
            if(a==0)
            {
                cout<<i+1;
           	 	a++;
            }
            else
            {
                cout<<","<<i+1;
            }
                
        }
        
    }
	
	
	return  0;
}

<think>我们正在解决YBT平台上的字符串匹配问题。根据引用[1]和引用[3],我们看到一种方法是通过哈希(Hash)将字符串转化为数值,然后比较数值来间接比较字符串。这种方法被称为字符串哈希,它可以在O(1)的时间内判断两个子串是否相等(在假设没有哈希冲突的情况下),从而优化字符串匹配的效率。 引用[1]提到:“通过把字符转化为数的方法 比较数也就是比较字符了”,这实际上就是字符串哈希的核心思想。 引用[3]则详细介绍了字符串哈希在解决回文串问题中的应用,并提到了如何避免负数以及冲突的问题。 因此,我们可以使用字符串哈希来解决YBT的字符串匹配问题。 ### 字符串哈希的基本原理 1. **预处理哈希前缀和**:对于一个字符串$s$,我们定义其前缀哈希数组$H$,其中$H[i]$表示从$s[0]$到$s[i-1]$(或$s[1]$到$s[i]$,取决于下标从0还是1始)的子串的哈希值。通常,我们采用多项式哈希: $$H[i] = (H[i-1] \times base + s[i]) \mod mod$$ 其中,$base$是一个大于字符集大小的基数(例如131, 13331等),$mod$是一个大质数(如$2^{64}$,这样可以利用unsigned long long的自然溢出)来减少冲突。 2. **计算子串哈希**:对于子串$s[l..r]$(闭区间),其哈希值可以通过前缀哈希数组计算: $$hash(l, r) = (H[r] - H[l-1] \times base^{r-l+1}) \mod mod$$ 注意:这里假设字符串下标从1始,且$H[0]=0$。如果下标从0始,则$l$和$r$需要相应调整。 3. **比较子串**:通过比较两个子串的哈希值,就可以判断它们是否相等。 ### 解决字符串匹配问题 假设我们有两个字符串:文本串$T$和模式串$P$。我们希望在$T$中查找$P$出现的所有位置。 步骤: 1. 预处理模式串$P$的哈希值$hash_P$。 2. 预处理文本串$T$的前缀哈希数组。 3. 遍历$T$中所有长度为$|P|$的子串,计算每个子串的哈希值,并与$hash_P$比较。如果相等,则当前位置匹配成功。 注意:为了避免哈希冲突,我们可以使用双哈希(即使用两个不同的基数和模数),但根据题目要求,有时候单哈希(尤其是模$2^{64}$)已经足够。 ### 代码实现(C++) 以下是一个使用字符串哈希解决字符串匹配问题的示例代码(假设字符串下标从1始): ```cpp #include <iostream> #include <cstring> #include <string> using namespace std; typedef unsigned long long ULL; const int N = 1000010, base = 131; ULL H[N], p[N]; // p[i] = base^i // 计算子串哈希值 ULL get_hash(int l, int r) { return H[r] - H[l-1] * p[r - l + 1]; } int main() { string T, P; cin >> T >> P; int n = T.size(), m = P.size(); // 将字符串调整为下标从1始 T = " " + T; P = " " + P; // 预处理文本串T的哈希前缀和 p[0] = 1; for (int i = 1; i <= n; i++) { H[i] = H[i-1] * base + T[i]; p[i] = p[i-1] * base; } // 计算模式串P的哈希值 ULL hash_P = 0; for (int i = 1; i <= m; i++) { hash_P = hash_P * base + P[i]; } // 在T中匹配P for (int i = 1; i <= n - m + 1; i++) { if (get_hash(i, i + m - 1) == hash_P) { // 匹配成功,输出位置(注意:题目中通常下标从1始,所以直接输出i) cout << i << endl; } } return 0; } ``` ### 注意事项 - 在实际问题中,需要注意字符串下标从0始还是从1始,上述代码调整为从1始。 - 使用自然溢出(即模$2^{64}$)可以简化代码,但要注意冲突的可能性。如果题目对正确性要求极高,建议使用双哈希。 - 时间复杂度:预处理$O(n)$,匹配过程$O(n)$,总时间复杂度$O(n+m)$,其中$n$是文本串长度,$m$是模式串长度。 ### 相关问题 1. 字符串哈希在什么情况下会出现冲突?如何降低冲突概率? 2. 除了字符串哈希,还有哪些字符串匹配算法?(如KMP、BM、Sunday等) 3. 如何用字符串哈希解决回文串问题? 4. 在YBT平台上,除了字符串匹配,还有哪些问题可以用字符串哈希解决?</think>### YBT 字符串匹配问题解决方案 针对YBT平台上的字符串匹配问题,核心解决方案是**字符串哈希(String Hashing)**技术。该方法将字符串转化为数值进行比较,避免了直接字符匹配的低效性,时间复杂度可达$O(n)$。以下是具体实现步骤和原理: --- #### 一、字符串哈希原理 1. **预处理哈希值**: - 定义哈希函数:$H[i] = (H[i-1] \times base + s[i]) \mod mod$ - $base$取质数(如131, 13331),$mod$取大质数(如$2^{64}$,利用自然溢出优化) 2. **子串哈希计算**: - 子串$s[l..r]$的哈希值:$hash(l, r) = (H[r] - H[l-1] \times base^{r-l+1}) \mod mod$ 3. **比较机制**: - 直接比较子串哈希值(数值比较替代字符串比较) > 关键优势:$O(1)$时间内比较任意子串[^1][^3]。 --- #### 二、算法实现步骤(C++) ```cpp #include <iostream> #include <string> using namespace std; typedef unsigned long long ULL; const int N = 1e6 + 10, base = 131; ULL H[N], p[N]; // H[i]:前缀哈希值;p[i]:base的i次幂 // 初始化哈希数组 void init_hash(string s) { p[0] = 1; for (int i = 1; i <= s.size(); i++) { H[i] = H[i-1] * base + s[i-1]; p[i] = p[i-1] * base; } } // 获取子串s[l..r]的哈希值 ULL get_hash(int l, int r) { return H[r] - H[l-1] * p[r - l + 1]; } int main() { string T, P; // T:文本串, P:模式串 cin >> T >> P; init_hash(T); // 预处理文本串哈希 ULL hashP = 0; for (char c : P) hashP = hashP * base + c; // 计算模式串哈希 int n = T.size(), m = P.size(); for (int i = 1; i <= n - m + 1; i++) { if (get_hash(i, i + m - 1) == hashP) { cout << "匹配位置: " << i << endl; } } return 0; } ``` --- #### 三、关键优化技巧 1. **避免哈希冲突**: - 使用双哈希(两个不同$base$和$mod$) - 特殊字符处理:如回文问题中插入分隔符`?`[^3] 2. **性能提升**: - 自然溢出法:利用`unsigned long long`自动取模$2^{64}$ - 预处理幂数组$p[i]$,避免重复计算 3. **边界处理**: - 字符串下标从1始($H[0]=0$) > 注:当模式串以通配符头时(如`LIKE '%abc'`),需调整算法逻辑[^4]。 --- #### 四、YBT平台应用场景 1. **基础字符串匹配**(如ybt 1455) 2. **回文串检测**(通过双向哈希比较) 3. **最长重复子串**(二分+哈希验证) 4. **字典树优化**(结合哈希加速前缀匹配) --- ### 相关问题 1. 字符串哈希的冲突概率如何计算?如何选择最优的$base$和$mod$? 2. 在回文串问题中,为什么要插入特殊字符(如`?`)?如何设计其数值? 3. 相比KMP算法,字符串哈希在哪些场景下更具优势? 4. 如何处理带通配符(如`*`或`?`)的字符串匹配问题?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值