牛客月赛40 (求子集gcd=x)

来点gcd
题意:
给定一个含有 n n n 个数的序列, m m m 次询问,每次查询给出一个整数 x x x,问是否能在序列中选出一些数,满足这些数的 g c d = x gcd=x gcd=x,如果只选出一个数,那么 g c d gcd gcd 就等于这个数。
思路:
首先要使选出的数的 g c d = x gcd=x gcd=x,那么这些数一定都是 x x x 的倍数。考虑到 n < = 2000 n<=2000 n<=2000,可以预处理所有答案,对于要查询的答案 i i i,枚举 i i i 的倍数,如果这个倍数出现过就进行 g c d gcd gcd(这个地方为什么呢,因为倍数肯定含 x x x 因子,要获得这个因子,越多的倍数进行 g c d gcd gcd 获得这个因子的可能越大),扫完一遍判断 g c d gcd gcd 是否为 i i i,如果不为 i i i,那么无论怎么选也不会选出 g c d = i gcd=i gcd=i 的序列。
考虑查询为 2 2 2 时, 2 , 4 , 6 , 8 2,4,6,8 2,4,6,8 这四个数,任选三个就可以得到 g c d = 2 gcd=2 gcd=2 的,但是少于三个, 4 4 4 8 8 8 这种,两个数 g c d gcd gcd 就不能获得 2 2 2(只能获得 2 2 2 的倍数。
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int maxn = 1e6 + 9;
const int mod = 1e9 + 7;
ll n, m;
bool v[maxn], ans[maxn];
void work()
{
	scanf("%lld %lld", &n, &m);
	for(int i = 1; i <= n; ++i) v[i] = ans[i] = 0;
	for(int i = 1; i <= n; ++i){
		int x;scanf("%d", &x);v[x] = 1;
	}
	for(int i = 1; i <= n; ++i){
		ll x = 0;
		for(ll j = i; j <= n; j += i) if(v[j])
			x = __gcd(x, j);
		if(x == i) ans[i] = 1;
	}
	while(m--)
	{
		int x;scanf("%d", &x);
		if(ans[x]) printf("YES\n");
		else printf("NO\n");
	}
}

int main()
{
//	ios::sync_with_stdio(0);
	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

数字匹配
思路:
这个题主要是判断是否匹配该怎么写
把两个数转化成二进制串,哈希一遍
然后暴力判断是否存在两个长度为 k k k 的连续子串是匹配的
code:
代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值