题解——再数17

T2的位置,并不算难,并且是对容斥原理的很好的应用。

题目描述

**给你一个有 n个正整数的列An。一个正整数 x 若满足在数列 An 中存在一个正整数 ai,使 x≡17(mod Ai),那么 x 就是一个‘ cost数’。 请问 1到 m的正整数 中, 有多少‘cost?’数?
小 co 看得一头雾水,只好又来请教你 **

输入

第一行两个 正整数 n和 m,意义见问题描述 。
第二行 n个正整数

输出

1个整数 , 表示 cost 的个数 。

数据范围

n <= 30 , Ai > 17 , m 和 Ai 保证在 int 范围内

题解

考虑容斥原理,我们要找出重复的数量。
提一下,容斥原理是可以从 3 扩展的。
说简单点,就是奇加偶减
开始引用原题解:(此人太懒了)
这时我们需要用个dfs枚举每个ai选与不选,若选出k个数,且k为奇数,则ans加上m/LCM(选出的数),若为偶数ans减去m/LCM(选出的数)。当然,还要加上优化,包括可行性剪枝(选出的数的LCM要小于等于m。由于ai >17,该剪枝十分有效)、优化搜索顺序(先搜大数)。时间复杂度:O(2nlogm)(实际小得多)。

AC代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll  N , M , A[ 62 ] , ans ;
inline ll read()
{
    ll s = 0,w = 1;
    char g = getchar();
    while(g<'0'||g>'9'){if(g=='-')w*=-1;g = getchar();}
    while(g>='0'&&g<='9'){s = s*10+g-'0';g = getchar();}
    return s*w;
}
void prepare_(){
	freopen("c17.in","r",stdin);
	freopen("c17.out","w",stdout);
	M = read() , N = read() - 17 ;
	for( register int i = 1 ; i <= M ; i++ )A[ i ] = read() ;
	sort( A + 1 , A + M + 1  ) ;
}
ll  gcd( ll  a , ll  b ){
	return ( b == 0 )?a:gcd( b , a%b ) ;
}
void dfs( ll now , ll h , ll s ){  //  h shows + -
	if( s >= N || now > M ) return ;
	ll t = s / gcd( s , A[ now ] ) * A[ now ] ;
	if ( h % 2 ) ans -= N / t ;
	else ans += N / t ;
	dfs( now + 1 , h + 1 , t ) ;
	dfs( now + 1 , h , s ) ;
}
int main(){
	prepare_();
	if( N < 0 ){ printf("0");return 0 ;}
	if( N == 1 ){ printf("1");return 0 ;}
	else dfs( 1 , 0 , 1 ) ;
	cout << ans + 1 ;
	return 0;
}

有疑惑和建议,可以留下评论或私我。

如果你喜欢我的文章,请点赞支持,谢谢。

posted @ 2019-05-25 16:24  蓝银杏-SSW  阅读(132)  评论(0编辑  收藏  举报
//结束