Frogs

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 4904    Accepted Submission(s): 1631

Problem Description
There are m stones lying on a circle, and n frogs are jumping over them.
The stones are numbered from 0 to m−1 and the frogs are numbered from 1 to n. The i-th frog can jump over exactly ai stones in a single step, which means from stone j mod m to stone (j+ai) mod m (since all stones lie on a circle).

All frogs start their jump at stone 0, then each of them can jump as many steps as he wants. A frog will occupy a stone when he reach it, and he will keep jumping to occupy as much stones as possible. A stone is still considered ``occupied" after a frog jumped away.
They would like to know which stones can be occupied by at least one of them. Since there may be too many stones, the frogs only want to know the sum of those stones' identifiers.

 
Input
There are multiple test cases (no more than 20), and the first line contains an integer t,
meaning the total number of test cases.

For each test case, the first line contains two positive integer n and m - the number of frogs and stones respectively (1≤n≤104, 1≤m≤109).

The second line contains n integers a1,a2,⋯,an, where ai denotes step length of the i-th frog (1≤ai≤109).

 
Output
For each test case, you should print first the identifier of the test case and then the sum of all occupied stones' identifiers.
 
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
 
Source
 

题意就是跳青蛙,通过分析会发现,就是步数a[i]与石头数m,通过gcd(a[i],m)之后,gcd的倍数的和。

因为重复的数只计算一次,所以要去重。

一开始想的是容斥去重,然而还是太捞了,。。。

这道题和队友讨论了3天,还问了学长,发现几个问题:

(1)如果直接枚举gcd的遍历,应该为去重他们的最小公倍数,也就是这样的。

for(ll j=;j<cnt;j++)
{
if(i&(<<j))
temp=temp*g[j]/gcd(temp,g[i]),jishu++;
}

(2)直接gcd的容斥枚举去重会超时,因为极限数据可能要枚举1<<36次,for一次的极限数据个人认为可能就是1e7再带点常数,1<<36次跑不出来,程序会崩。所以这种容斥是不可以的,虽然想法真的很好,但是真的过不去。所以,最后放弃了这种思路,其实还是可以容斥的,但是是有技巧的容斥。

直接看的题解,所以也不好说什么,毕竟是人家的劳动成果,只是分析一下。

做法一:

欧拉函数的延伸用法:小于或等于n的数中,与n互质的数的总和为:φ(n) * n / 2  (n>1)。

做法二:

枚举m的因子个数,这样就会少很多,就不存在超时的问题了。

以上两种做法的具体题解传送门:HDU 5514 Frogs(欧拉函数+数论YY)

直接贴代码吧。

代码1(欧拉函数):

 //欧拉函数的公式求解
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii; const double PI=acos(-1.0);
const double eps=1e-;
const ll mod=1e9+;
const int inf=0x3f3f3f3f;
const int maxn=1e5+;
const int maxm=+;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); ll a[maxn],n,m; ll gcd(ll a,ll b)
{
return b==?a:gcd(b,a%b);
} ll euler(ll n)
{
ll ans=n;
for(int i=;i*i<=n;i++){
if(n%i==){
ans=ans/i*(i-);
while(n%i==) n/=i;
}
}
if(n>) ans=ans/n*(n-);
return ans;
} bool solve(int x)
{
for(int i=;i<n;i++){
if(x%a[i]==) return true;
}
return false;
} int main()
{
int t;
scanf("%d",&t);
for(int cas=;cas<=t;cas++){
memset(a,,sizeof(a));
scanf("%lld%lld",&n,&m);
for(int i=;i<n;i++){
scanf("%d",a+i);
a[i]=gcd(a[i],m);
}
ll ans=;
for(int i=;i*i<=m;i++){
if(m%i) continue;
if(solve(i)) ans+=(ll)euler(m/i)*m/;
if(i*i==m||i==) continue;
if(solve((m/i))) ans+=(ll)euler(i)*m/;
}
printf("Case #%d: %lld\n",cas,ans);
}
}

代码2(容斥原理):

 //容斥定理
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii; const double PI=acos(-1.0);
const double eps=1e-;
const ll mod=1e9+;
const int inf=0x3f3f3f3f;
const int maxn=1e5+;
const int maxm=+;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); ll gcd(ll a,ll b)
{
return b==?a:gcd(b,a%b);
} ll g[maxn],fac[maxn];
int tp[maxn],num[maxn],vis[maxn]; int main()
{
int t;
scanf("%d",&t);
for(int cas=;cas<=t;cas++){
ll n,m;
scanf("%lld%lld",&n,&m);
int ok=;
for(int i=;i<n;i++){
scanf("%lld",&g[i]);
g[i]=gcd(g[i],m);
if(g[i]==) ok=;
}
if(ok==){
printf("Case #%d: %lld\n",cas,m*(m-)/);
continue;
}
sort(g,g+n);
n=unique(g,g+n)-g;
memset(vis,,sizeof(vis));
memset(num,,sizeof(num));
int cnt=;
for(ll i=;i*i<=m;i++){
if(i*i==m) fac[cnt++]=m/i;
else if(m%i==) fac[cnt++]=i,fac[cnt++]=m/i;
}
sort(fac,fac+cnt);
int cnt1=;
for(int i=;i<n;i++){
if(!vis[i]){
tp[cnt1++]=g[i];
for(int j=;j<n;j++)
if(g[j]%g[i]==) vis[j]=;
}
}
memset(vis,,sizeof(vis));
for(int i=;i<cnt;i++){
for(int j=;j<cnt1;j++){
if(fac[i]%tp[j]==){
vis[i]=;
break;
}
}
}
ll sum=;
for(int i=;i<cnt;i++){
if(num[i]!=vis[i]){
sum+=m*(m/fac[i]-)/*(vis[i]-num[i]);
for(int j=i+;j<cnt;j++)
if(fac[j]%fac[i]==)
num[j]=num[j]+vis[i]-num[i];
}
}
printf("Case #%d: %lld\n",cas,sum);
}
return ;
}

贴一下我们想了3天的错误代码,纪念一下。

代码(错误的):

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii; const double PI=acos(-1.0);
const double eps=1e-;
const ll mod=1e9+;
const int inf=0x3f3f3f3f;
const int maxn=1e5+;
const int maxm=+;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1 ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
} ll sum(ll x,ll n)
{
ll temp=(n-)/x;
return temp*x+(temp*(temp-)/)*x;
} ll a[maxn]; int main()
{
ll t;
scanf("%lld",&t);
for(int cas=;cas<=t;cas++)
{
ll n,m;
scanf("%lld%lld",&n,&m);
ll h=;
for(int i=;i<n;i++)
{
ll x;
scanf("%lld",&x);
a[h++]=gcd(x,m);
}
vector<ll> g;
sort(a,a+h);
for(int i=h-;i>=;i--){
int flag=;
for(int j=i-;j>=;j--){
if(a[i]%a[j]==) flag=;
}
if(!flag) g.push_back(a[i]);
}
int cnt=g.size();
ll ans=;
for(ll i=;i<(1ll<<cnt);i++)
{
ll temp=,jishu=;
for(ll j=;j<cnt;j++)
{
if(i&(<<j))
temp=temp*g[j]/gcd(temp,g[i]),jishu++;
}
if(jishu==)continue;
if(jishu&) ans+=sum(temp,m);
else ans-=sum(temp,m);
}
printf("Case #%d: %lld\n",cas,ans);
}
}

到此为止,拜拜,再也不看这个题了。

HDU 5514.Frogs-欧拉函数 or 容斥原理的更多相关文章

  1. HDU 5514 Frogs 欧拉函数

    题意: 有\(m(1 \leq m \leq 10^9)\)个石子排成一圈,编号分别为\(0,1,2 \cdots m-1\). 现在在\(0\)号石头上有\(n(1 \leq n \leq 10^4 ...

  2. HDU 1695 GCD (欧拉函数,容斥原理)

    GCD Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis ...

  3. hdu 1695 GCD (欧拉函数+容斥原理)

    GCD Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  4. hdu 1695 GCD (欧拉函数、容斥原理)

    GCD Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis ...

  5. HDU 2824 简单欧拉函数

    1.HDU 2824   The Euler function 2.链接:http://acm.hdu.edu.cn/showproblem.php?pid=2824 3.总结:欧拉函数 题意:求(a ...

  6. HDU 1695 GCD 欧拉函数+容斥定理

    输入a b c d k求有多少对x y 使得x在a-b区间 y在c-d区间 gcd(x, y) = k 此外a和c一定是1 由于gcd(x, y) == k 将b和d都除以k 题目转化为1到b/k 和 ...

  7. HDU 1695 GCD 欧拉函数+容斥定理 || 莫比乌斯反演

    GCD Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  8. GuGuFishtion HDU - 6390 (欧拉函数,容斥)

    GuGuFishtion \[ Time Limit: 1500 ms\quad Memory Limit: 65536 kB \] 题意 给出定义\(Gu(a, b) = \frac{\phi(ab ...

  9. HDU 2588 GCD (欧拉函数)

    GCD Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Submit Status De ...

  10. hdu 6434 Count (欧拉函数)

    题目链接 Problem Description Multiple query, for each n, you need to get $$$$$$ \sum_{i=1}^{n} \sum_{j=1 ...

随机推荐

  1. maven中用yuicompressor和closure-compiler对js、css文件进行压缩

    转载自:http://matychen.iteye.com/blog/1477350 项目采用maven构建的时候,需要压缩js,css等,网上找了相关资料,自己综合了下-  直接放代码: <! ...

  2. String StrigBuffer StringBuilder 浅解

    1.String是最基本的字符串类,用于表示字符串. 特点:对象内容不可变,但可以通过指向不同的对象来“表示”不同的内容. 使用场景:如果不涉及到内容改变,可以使用String. 注意:如果想将Str ...

  3. 1-shell学习(bash)

    1.为什么需要学习shell: (1)通用性,基本上所有的linux机器都会支持 (2)文字传输操作更快 (3)以后的系统管理需要使用 2.知识点: (1)变量相关:

  4. 51Nod 1182 完美字符串

    Input示例 dad Output示例 77 #include "bits/stdc++.h" using namespace std; #define LL long long ...

  5. [洛谷P1707] 刷题比赛

    洛谷题目连接:刷题比赛 题目背景 nodgd是一个喜欢写程序的同学,前不久洛谷OJ横空出世,nodgd同学当然第一时间来到洛谷OJ刷题.于是发生了一系列有趣的事情,他就打算用这些事情来出题恶心大家-- ...

  6. 两台linux服务器之间免密scp,在A机器上向B远程拷贝文件

    两台linux服务器之间免密scp,在A机器上向B远程拷贝文件 操作步骤:1.在A机器上,执行ssh-keygen -t rsa,一路按Enter,不需要输入任何内容.(如有提示是否覆盖,可输入y后按 ...

  7. bzoj 2956: 模积和 ——数论

    Description 求∑∑((n mod i)*(m mod j))其中1<=i<=n,1<=j<=m,i≠j. Input 第一行两个数n,m. Output 一个整数表 ...

  8. dot.js使用心得

    一.dot.js介绍 最近用到的数据模板引擎有很多,今天讲的doT.js也是其中一种. doT.js的特点是体积小,速度快,并且不依赖其他插件. 官网下载:http://olado.github.io ...

  9. No 'Access-Control-Allow-Origin' Ajax跨域访问解决方案

    No 'Access-Control-Allow-Origin' header is present on the requested resource. 当使用ajax访问远程服务器时,请求失败,浏 ...

  10. java===字符串常用API介绍(转)

    本文转自:http://blog.csdn.net/crazy_kid_hnf/article/details/55102861 字符串基本操作 1.substring(from,end)(含头不含尾 ...