您的位置:首页 > 其它

HDU 5514 Frogs(容斥)

2016-09-08 16:41 363 查看
给你n个步长,圈长m,从0到m−1

然后问你这n个步长,能走到那些位置,求位置之和

gcd(a[i],m)=k[i],说明第i个步长,能走m/k个位置

然后会有重复计算,那么就需要容斥,但是n有1W,不好直接容斥

该怎么办呢,考虑m的因子,比如有tot个因子

如果k[i]是一些因子的倍数,那么说明这些因子的步长都会被走过

所以可以考虑,每个因子,应该走几次vis[j],已经被走了几次num[j]

这个已经被走是什么概念,就是它的因子走一次,说明它也走了一次

所以可以O(num2因子)的复杂度解决

比如对于因子6,如果原本的步长里有2

那么它应该走1次,因为有因子6的话,肯定有2和3

那么2也应该走一次,6就被走了一次,3没有走,所以6应该走一次,已经被走1次,所以6算0次

如果步长里还有3,那么6应该走1次,已经被走2次,就要算−1次,减去

讲道理这种方法很巧妙,我还是太弱了,想到了因子2的复杂度,还是没做出来

代码:

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           10005
#define   MAXN          1000005
#define   maxnode       205
#define   sigma_size    2
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,LL>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair
#define   limit         10000

//const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 0x3f3f;
//const double pi    = acos(-1.0);
const double inf   = 1e18;
const double eps   = 1e-9;
const LL     mod   = 1e8+9;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/

int a[MAX];
int yin[MAX];
int vis[MAX];
int num[MAX];

int gcd(int a,int b){
if(!b) return a;
return gcd(b,a%b);
}

int main(){
int t,kase=0;
cin>>t;
while(t--){
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++) scanf("%d",&a[i]);
int tot=0;
mem(vis,0);
mem(num,0);
for(int i=1;i<=sqrt(m);i++){
if(m%i==0){
yin[tot++]=i;
if(m/i!=i) yin[tot++]=m/i;
}
}
sort(yin,yin+tot);
for(int i=0;i<n;i++){
int k=gcd(a[i],m);
for(int j=0;j<tot;j++){
if(yin[j]%k==0) vis[j]=1;
}
}
vis[tot-1]=0;
LL ans=0;
for(int i=0;i<tot;i++){
if(vis[i]!=num[i]){
int x=(m-1)/yin[i];
ans+=(LL)x*(x+1)/2*yin[i]*(vis[i]-num[i]);
int y=vis[i]-num[i];
for(int j=i+1;j<tot;j++){
if(yin[j]%yin[i]==0) num[j]+=y;
}
}
}
kase++;
printf("Case #%d: ",kase);
cout<<ans<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: