这题很容易转化到一个容斥计数问题。而用指数复杂度的枚举计数法显然会挂,只能考虑别的方法。

首先将a[i]用gcd(a[i], m)替换,排序去重后得到一组m的约数,而m不超过1e9,因此m的所有约数最多在1000左右。

假设数组a只含有2,3两个元素,那么显然答案应该是f(2) + f(3) - f(6),f(i)表示只有i的情况下的答案。

2和3的系数是1,6的系数是-1,其余系数为0。

根据容斥原理:对于某个特定的约数,若存在数组a的一个子集其lcm为该约数,那么若集合元素个数为偶数,贡献-1,若为奇数,贡献1。

而最终的答案一定由所有约数合成,其系数取值{-1,0,1}。

因此我们考虑数组a的前m个数,其对应的系数分布是可以确定的。

加入第m+1个数时,显然新的集合必然由原集合的子集并上新元素得到,分别考虑m的所有约数k,其对应的系数为op(k)

若op(k)为-1,则说明偶数子集的个数比奇数子集的个数多1,若我们添如新元素x,则恰好使得奇数子集个数比偶数多1,但此时贡献

不是对k的,而是对lcm(k, x),用公式表示就是:

op(lcm(k, x)) += op(k) * (-1).

其余情形类似。

最终答案是ans = sigma(op(i) * f(i)), i | m.

这样我们只需最多进行1000次遍历就可使得元素个数加一,总复杂度约为O(1e6)。

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <string>
#include <vector>
#include <set>
#include <cmath>
#include <ctime>
#include <cassert>
#define lson (u << 1)
#define rson (u << 1 | 1)
#define cls(i, j) memset(i, j, sizeof i)
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef __int64 ll;
const double eps = 1e-;
const double pi = acos(-1.0);
const int maxn = 1e4 + ;
const int maxm = 4e4 + ;
const int inf = 0x3f3f3f3f;
const ll linf = 0x3fffffffffffffff;
const ll mod = 1e9 + ; map<ll, int> mapi;
int n;
ll a[maxn], m;
int prime[maxm], k;
bool vis[maxm];
ll fact[maxn], nf;
int cnt[maxn];
ll table[maxn], nt;
int op[maxn];
int op1[maxn];
ll ans; ll gcd(ll a, ll b) { return !b ? a : gcd(b, a % b); } void init(){
cls(vis, );
k = ;
for(int i = ; i < maxm; i++){
if(vis[i]) continue;
prime[k++] = i;
for(int j = i * ; j < maxm; j += i) vis[j] = ;
}
} void dfs(int next, ll num){
if(next >= nf){
table[nt++] = num;
mapi[num] = nt - ;
return;
}
ll tem = num;
for(int i = ; i <= cnt[next]; i++){
dfs(next + , tem);
tem *= fact[next];
}
} ll f(ll num){
ll tem = (m - ) / num;
return tem * (tem + ) / * num;
} void factorize(){
nf = ;
ll m1 = m;
int mid = (int)sqrt(m);
for(int i = ; prime[i] <= mid; i++){
if(m % prime[i]) continue;
fact[nf++] = prime[i];
cnt[nf - ] = ;
while(m % prime[i] == ) ++cnt[nf - ], m /= prime[i];
mid = (int)sqrt(m);
}
if(m != ) fact[nf++] = m, cnt[nf - ] = ;
m = m1;
} ll solve(){
mapi.clear();
int n1 = ;
for(int i = ; i < n; i++){
ll tem = a[i] % m;
if(!tem) continue;
a[n1++] = gcd(m, tem);
}
n = n1;
sort(a, a + n);
n = unique(a, a + n) - a;
cls(vis, );
for(int i = ; i < n; i++){
for(int j = i + ; j < n; j++){
if(a[i] % a[j] == ) vis[i] = ;
else if(a[j] % a[i] == ) vis[j] = ;
}
}
n1 = ;
for(int i = ; i < n; i++) if(!vis[i]) a[n1++] = a[i];
n = n1;
sort(a, a + n);
factorize();
nt = ;
dfs(, );
cls(op, );
ans = ;
for(int i = ; i < n; i++){
cls(op1, );
for(int j = ; j < nt; j++){
ll tem = a[i] / gcd(a[i], table[j]) * table[j];
if(tem >= m) continue;
op1[mapi[tem]] += -op[j];
}
++op1[mapi[a[i]]];
for(int j = ; j < nt; j++) op[j] += op1[j];
}
// for(int i = 0; i < nt; i++) printf("%d ", op[i]);
// puts("");
for(int i = ; i < nt; i++) ans += op[i] * f(table[i]);
return ans;
} int main(){
// freopen("in.txt", "r", stdin);
int T, kase = ;
init();
scanf("%d", &T);
while(T--){
scanf("%d%I64d", &n, &m);
for(int i = ; i < n; i++) scanf("%I64d", &a[i]);
ll ans = solve();
printf("Case #%d: %I64d\n", ++kase, ans);
}
return ;
}

hdu5514Frogs(2015ACM-ICPC沈阳赛区F题)的更多相关文章

  1. 2015ACM/ICPC亚洲区长春站 F hdu 5533 Almost Sorted Array

    Almost Sorted Array Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Ot ...

  2. HDU 5901 Count primes (1e11内的素数个数) -2016 ICPC沈阳赛区网络赛

    题目链接 题意:求[1,n]有多少个素数,1<=n<=10^11.时限为6000ms. 官方题解:一个模板题, 具体方法参考wiki或者Four Divisors. 题解:给出两种代码. ...

  3. hdu 4461 第37届ACM/ICPC杭州赛区I题

    题意:给两个人一些棋子,每个棋子有其对应的power,若b没有或者c没有,或者二者都没有,那么他的total power就会减1,total power最少是1,求最后谁能赢 如果b或c出现的话,fl ...

  4. zoj 3662 第37届ACM/ICPC长春赛区H题(DP)

    题目:给出K个数,使得这K个数的和为N,LCM为M,问有多少种 f[i][j][k]表示选i个数,总和为j,最小公倍数为k memery卡的比较紧,注意不要开太大,按照题目数据开 这种类型的dp也是第 ...

  5. hdu 4463 第37届ACM/ICPC杭州赛区K题 最小生成树

    题意:给坐标系上的一些点,其中有两个点已经连了一条边,求最小生成树的值 将已连接的两点权值置为0,这样一定能加入最小生成树里 最后的结果加上这两点的距离即为所求 #include<cstdio& ...

  6. 2015 ICPC 沈阳站M题

    M - Meeting Time Limit:6000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit ...

  7. HDU 5532 / 2015ACM/ICPC亚洲区长春站 F.Almost Sorted Array

    Almost Sorted Array Problem Description We are all familiar with sorting algorithms: quick sort, mer ...

  8. 2016 ICPC大连站---F题 Detachment

    题意:输入一个x,将x拆分成一些小的数(这些数不能相同,即x=a1+a2+......   ai!=aj when i!=j),然后这些数相乘得到一个成积(s=a1*a2*......),求最大的乘积 ...

  9. HDU 5894 hannnnah_j’s Biological Test (组合数学) -2016 ICPC沈阳赛区网络赛

    题目链接 #include <map> #include <queue> #include <math.h> #include <stdio.h> #i ...

随机推荐

  1. Java基础之创建窗口——使用边界布局管理器(TryBorderLayout)

    控制台程序. 边界布局管理器最多能在容器中放置5个组件.在这种布局管理器中,可以把组件放在容器的任意一个边界上,也可以把组件放在容器的中心.每个位置只能放置一个组件.如果把组件放置在已被占用的边界上, ...

  2. JMX超详细解读

    一.JMX的定义 JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架.JMX是一套标准的代理和服务,实际上,用户可以在任何Java应用程序中使用这些代理和 ...

  3. unresolved external symbol __report_rangecheckfailure 解决思路

    __report_rangecheckfailure  是用来检查堆栈缓存溢出的,如果编译的时候打开GS(project property-->Configuration properties- ...

  4. 转:python webdriver API 之对话框处理

    页面上弹出的对话框是自动化测试经常会遇到的一个问题:很多情况下对话框是一个 iframe,如上一节中介绍的例子,处理起来稍微有点麻烦:但现在很多前端框架的对话框是 div 形式的,这就让我们的处理变得 ...

  5. How to use Ubuntu Linux in virtual box

    安装git : yum install git 查询包: rpm -ql git 打开文件夹目录: nautilus 目录路径

  6. 科学计算器的Java实现

    简易的科学计算器的实现 ---Java版 import javax.swing.*;//新的窗口组件包 import java.awt.*; import java.awt.event.*; publ ...

  7. [原创]java WEB学习笔记61:Struts2学习之路--通用标签 property,uri,param,set,push,if-else,itertor,sort,date,a标签等

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  8. Spring 中 Xml配置文件属性的说明

    Xml配置文件属性的说明: <bean id="TheAction" ⑴ class="net.xiaxin.spring.qs.UpperAction" ...

  9. paper 1:图像特征提取

    特征提取是计算机视觉和图像处理中的一个概念.它指的是使用计算机提取图像信息,决定每个图像的点是否属于一个图像特征.特征提取的结果是把图像上的点分为不同的子集,这些子集往往属于孤立的点.连续的曲线或者连 ...

  10. Mysql索引总结(二)

    在数据库表中,对字段建立索引可以大大提高查询速度.假如我们创建了一个 mytable表: ) NOT NULL ); 在查找username="admin"的记录 SELECT * ...