HDU 5514 Frogs(容斥)
2016-01-05 14:51
351 查看
Description
有n只青蛙和m块围成一圈的石头(编号0~m-1),初始状态所有青蛙都在第0块石头上,每只青蛙一次可以往前跳ai块石头,问最终所有被青蛙踩过的石头的编号和
Input
第一行为一整数T表示用例组数,每组用例第一行为两个整数n和m表示青蛙数量和石头数量,第二行为n个整数ai表示每只青蛙一次可以跳的石头数(1≤n≤10^4, 1≤m≤10^9,1<=ai<=10^9)
Output
对于每组用例,输出被青蛙踩过的石头的编号和
Sample Input
3
2 12
9 10
3 60
22 33 66
9 96
81 40 48 32 64 16 96 42 72
Sample Output
Case #1: 42
Case #2: 1170
Case #3: 1872
Solution
显然每只青蛙踩过的石头编号构成一个首项为0公差为ai的等差数列,gcd(ai,m)项,那么最后所有被青蛙踩过的石头编号都是m的因子(0除外),那么首先处理处m的所有因子,然后对m的因子进行容斥,用num[i]表示m的第i个因子被重复计算的次数(初始为0),vis[i]标记m的第i个因子是否被访问,对于每个ai,标记所有可以整除gcd(ai,m)的因子(注意取消最后一个因子m的标记,因为第m块石头其实是第0块),对于num[i]!=vis[i]的因子,ans+=m/p[i](m/p[i]-1)/2*p[i](vis[i]-num[i]),然后对所有可以被p[i]整除的因子p[j],num[j]+=vis[i]-num[i],表示因子j被重复计算了vis[i]-num[i]次
Code
有n只青蛙和m块围成一圈的石头(编号0~m-1),初始状态所有青蛙都在第0块石头上,每只青蛙一次可以往前跳ai块石头,问最终所有被青蛙踩过的石头的编号和
Input
第一行为一整数T表示用例组数,每组用例第一行为两个整数n和m表示青蛙数量和石头数量,第二行为n个整数ai表示每只青蛙一次可以跳的石头数(1≤n≤10^4, 1≤m≤10^9,1<=ai<=10^9)
Output
对于每组用例,输出被青蛙踩过的石头的编号和
Sample Input
3
2 12
9 10
3 60
22 33 66
9 96
81 40 48 32 64 16 96 42 72
Sample Output
Case #1: 42
Case #2: 1170
Case #3: 1872
Solution
显然每只青蛙踩过的石头编号构成一个首项为0公差为ai的等差数列,gcd(ai,m)项,那么最后所有被青蛙踩过的石头编号都是m的因子(0除外),那么首先处理处m的所有因子,然后对m的因子进行容斥,用num[i]表示m的第i个因子被重复计算的次数(初始为0),vis[i]标记m的第i个因子是否被访问,对于每个ai,标记所有可以整除gcd(ai,m)的因子(注意取消最后一个因子m的标记,因为第m块石头其实是第0块),对于num[i]!=vis[i]的因子,ans+=m/p[i](m/p[i]-1)/2*p[i](vis[i]-num[i]),然后对所有可以被p[i]整除的因子p[j],num[j]+=vis[i]-num[i],表示因子j被重复计算了vis[i]-num[i]次
Code
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; #define maxn 11111 #define INF 0x3f3f3f3f typedef long long ll; int gcd(int a,int b) { if(b==0)return a; return gcd(b,a%b); } int main() { int T,n,m,a,num[maxn],p[maxn],vis[maxn],res,Case=1; scanf("%d",&T); while(T--) { memset(num,0,sizeof(num)); memset(vis,0,sizeof(vis)); res=0; scanf("%d%d",&n,&m); for(int i=1;i*i<=m;i++) if(m%i==0) { p[res++]=i; if(i*i!=m)p[res++]=m/i; } sort(p,p+res); for(int i=1;i<=n;i++) { scanf("%d",&a); int g=gcd(a,m); for(int j=0;j<res;j++) if(p[j]%g==0)vis[j]=1; } vis[res-1]=0; ll ans=0; for(int i=0;i<res;i++) if(vis[i]!=num[i]) { ll x=m/p[i]; ans+=x*(x-1)/2*p[i]*(vis[i]-num[i]); for(int j=i+1;j<res;j++) if(p[j]%p[i]==0) num[j]+=vis[i]-num[i]; } printf("Case #%d: %lld\n",Case++,ans); } return 0; }
相关文章推荐
- Python之IPython开发实践
- [web安全] web安全小知识点汇总
- 调试一个MFC的点云可视化(PCL)程序
- lintcode 中等题:partition array 数组划分
- Android:图形
- LeetCode106 Construct Binary Tree from Inorder and Postorder Traversal
- php视频直播
- JQuery DataTables学习
- Instance Three: SELECT * FROM DATABASE
- Mongodb 权限管理
- 《swift2.0 官方教程中文版》 第2章-23泛型
- 表的聚合函数
- easy ui window 相关属性
- ubantu下编译安装mysql5.6.28文档
- leetcode第23题 - 链表节点两两置换
- EXSI 5.5 虚拟机,使用*-flat.vmdk恢复的方法
- Beginning Python Chapter7
- 2015工作总结
- 仿QQ列表左滑删除效果
- Joiner transformation(2) 优化