9.4模拟赛解题报告
Posted yjkhhh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了9.4模拟赛解题报告相关的知识,希望对你有一定的参考价值。
(T1~~~~计数~~~~count)
题目描述
给出(m)个数(a[1],a[2],…,a[m])
求1~n中有多少数不是(a[1],a[2],…,a[m])的倍数。
对于(60\%)的数据(1<=n<=10^6)对于另外(20%)的数据,(m=2)
对于(100\%)的数据,(1<=n<=10^9,0<m<=20,1<=a[i]<=10^9)
题解
这道题显然是容斥
我们可以统计1~n中有多少数是某个(a_i)的倍数
显然1~n中(x)的倍数有(n/x)个
容斥:加上每个(a_i)的倍数个数,减去每个同时是(a_i)和(a_j)的倍数的数的个数,加上每个同时是(a_i,a_j,a_k)的倍数的数的个数……
[sum_{1leq b_1< b_2 ...< b_kleq n}(-1)^{k-1}frac{n}{lcm(a_{b_1},a_{b_2}...a_{b_k})}]
(2^m)枚举二进制表示是哪些数的倍数,求lcm即可
一开始求lcm直接暴力,跑得有些慢,求lcm的复杂度较大
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int n,m,a[25],maxx;
long long ans;
int gcd(int x,int y){
if(!y) return x;
return gcd(y,x%y);
}
int lcm(int x,int y){
if(x<y) swap(x,y);
return x*y/gcd(x,y);
}
long long solve(int x){
int t=1,f=-1;
for(int i=0;i<m;i++)
if((x>>i)&1){
t=lcm(t,a[i+1]);
f=-f;
}
return n/t*f;
}
int main()
{
// freopen("count.in","r",stdin);
// freopen("count.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d",&a[i]);
maxx=(1<<m)-1;
for(int i=1;i<=maxx;i++)
ans+=solve(i);
printf("%d
",n-ans);
// fclose(stdin); fclose(stdout);
return 0;
}
我们发现,求(lcm(a_{b_1},a_{b_2},...,a_{b_k}))时
我们一定求过(lcm(a_{b_1},a_{b_2},...,a_{b_{k-1}}))了
我们可以记录下每次求得的lcm值,求k个数的lcm可以用k个数里面的k-1个数的lcm直接求出来
复杂度(O(2^m(m+log a_i)))
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
LL n,m,a[25],maxx,ans;
bool mark[1000010];
LL lcm[1048580],f[1048580];
LL gcd(LL x,LL y){
if(!y) return x;
return gcd(y,x%y);
}
LL Lcm(LL x,LL y){
if(x<y) swap(x,y);
return x*y/gcd(x,y);
}
LL solve(LL x){
for(LL i=0;i<m;i++)
if((x>>i)&1){
lcm[x]=Lcm(a[i+1],lcm[x-(1<<i)]);
f[x]=-f[x-(1<<i)];
break;
}
return f[x]*n/lcm[x];
}
int main()
{
// freopen("count.in","r",stdin);
// freopen("count.out","w",stdout);
scanf("%lld%lld",&n,&m);
if(n<=1000000){
int x;
for(int i=1;i<=m;i++){
scanf("%d",&x);
for(int j=x;j<=n;j+=x)
mark[j]=1;
}
for(int i=1;i<=n;i++)
if(!mark[i]) ans++;
printf("%lld
",ans);
fclose(stdin); fclose(stdout);
return 0;
}
for(int i=1;i<=m;i++)
scanf("%lld",&a[i]);
maxx=(1<<m)-1;
lcm[0]=1; f[0]=-1;
for(LL i=1;i<=maxx;i++)
ans+=solve(i);
printf("%lld
",n-ans);
// fclose(stdin); fclose(stdout);
return 0;
}
(T2~~~~区间第k大~~~~kth)
题目描述
一个区间的价值定义为该区间中的最大值减最小值
给定(n)个数,求所有区间价值中,第(k)大值为多少。
以上是关于9.4模拟赛解题报告的主要内容,如果未能解决你的问题,请参考以下文章