1138 - 震惊,99%+的中国人都会算错的问题
Time Limit:4s Memory Limit:128MByte
Submissions:316Solved:88
DESCRIPTION
众所周知zhu是一个大厨,zhu一直有自己独特的咸鱼制作技巧.
tang是一个咸鱼供应商,他告诉zhu在他那里面有N条咸鱼(标号从1到N)可以被用来制作.
每条咸鱼都有一个咸鱼值Ki,初始时所有Ki都是0.
zhu是一个特别的人,他有M个咸数(咸鱼数字), 对于每个咸数x,他都会让所有满足标号是x倍数的咸鱼的咸鱼值异或上1.
zhu现在想知道经过了这M个咸数的筛选之后,最终有多少条的咸鱼的咸鱼值是1?
INPUT
输入的第一行包含一个整数
T(1≤T≤1000),表示有
T组数据.
对于每组数据:
输入第一行只有两个整数 N(1≤N≤109), M(1≤M≤15).
接下来一行有 M个整数,依次对应zhu的每个咸数( 1≤咸数≤2∗105).
对于每组数据:
输入第一行只有两个整数 N(1≤N≤109), M(1≤M≤15).
接下来一行有 M个整数,依次对应zhu的每个咸数( 1≤咸数≤2∗105).
OUTPUT
对于每组数据,输出答案.
SAMPLE INPUT
2
10 1
3
10 1
1
10 1
3
10 1
1
SAMPLE OUTPUT
3
10
10
题目链接:
题目大意:
一开始编号1-n中的所有数字都为0,告诉你m个数字,将所有标号为这m个数字的倍数的值都^1,问最后有多少个数字值为1
解题思路:
考虑到n的范围很大,而m最多只有15个值,我们用容斥来做。
因为每次都是编号满足条件的值与1异或,所以值一直在1、0之间变动,因此不能像之前的找倍数那样直接加减。
(比如n=10,m=2,k1 k2分别为2 3时,编号6的值最终结果为0)
换个思路想就是这个格子是否被统计了奇数次(奇数次为1偶数次为0),按二进制考虑,所以满足A*B的倍数时就应在总数中-2*数量,当满足A*B*C的倍数时就+2^2*数量,这样……即±2^(位数-1)*数量。
Mycode:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAX = 10005;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
int t, m;
LL a[20], ans, n;
LL gcd(LL a, LL b)
{
return b == 0 ? a : gcd(b, a % b);
}
LL lcm(LL a, LL b)
{
return a / gcd(a, b) * b;
}
int main()
{
scanf("%d",&t);
while(t--)
{
ans = 0;
scanf("%lld%d",&n,&m);
for(int i = 0; i < m; ++i)
scanf("%lld",&a[i]);
for(int i = 1; i < (1 << m); ++i)
{
LL mul = 1;
int bits = 0;
for(int j = 0; j < m; ++j)
{
if(i & (1 << j))
{
bits++;
mul = lcm(mul, a[j]);
if(mul > n) break;
}
}
if(bits & 1)
ans += n / mul * (1 << (bits - 1));
else
ans -= n / mul * (1 << (bits - 1));
}
printf("%lld\n", ans);
}
return 0;
}