标签:lin 原理 multiple res 暴力 i++ 应该 href can
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 4843 Accepted Submission(s): 1605
解析 这道题真的非常好,有技巧的容斥。
AC代码
#include<iostream> #include<stdio.h> #include<cstring> #include<algorithm> #include<math.h> using namespace std; #define maxn 10005 int gcd(int a,int b) { return b==0?a:gcd(b,a%b); } //每个青蛙,可以跳到gcd(m,a[i])*k的位置 int ppp[maxn]; int num[maxn],vis[maxn]; int main() { int tt;scanf("%d",&tt); for(int cas=1;cas<=tt;cas++) { int n,m; int cnt = 0; memset(vis,0,sizeof(vis)); memset(num,0,sizeof(num)); scanf("%d%d",&n,&m); for(int i=1;i<=sqrt(m);i++)//把因子全部筛出来 { if(m%i==0) { ppp[cnt++]=i; if(i*i!=m) ppp[cnt++]=m/i; } } sort(ppp,ppp+cnt); for(int i=0;i<n;i++) { int x;scanf("%d",&x); int kk = gcd(x,m); for(int j=0;j<cnt;j++) if(ppp[j]%kk==0)//说明这个因子的所有,都是可以被跳到的位置 vis[j]=1; } vis[cnt-1]=0;//显然 m是不可能被跳到的 long long ans = 0; for(int i = 0; i < cnt; i++) { if(vis[i] != num[i]) { int t = (m-1)/ppp[i]; ans += (long long)t*(t+1)/2 * ppp[i] * (vis[i]-num[i]); //容斥一波 //一开始vis[i] - num[i] = 1的 //对于每个因数,如果重复计算了,在之后,减去就好了 t = vis[i] - num[i]; for(int j = i; j < cnt; j++) if(ppp[j]%ppp[i] == 0) num[j] += t; } } printf("Case #%d: %lld\n",cas,ans); } }
wa的代码,暴力容斥,极限数据是36个gcd 应该直接爆复杂度了,不应该是wa的
#include <bits/stdc++.h> #define pb push_back #define mp make_pair #define fi first #define se second #define all(a) (a).begin(), (a).end() #define fillchar(a, x) memset(a, x, sizeof(a)) #define huan printf("\n") #define debug(a,b) cout<<a<<" "<<b<<" "<<endl #define ffread(a) fastIO::read(a) using namespace std; typedef long long ll; typedef pair<int,int> pii; const int maxn=1e4+10; ll gcd(ll a,ll b) { return b?gcd(b,a%b):a; } ll sum(ll x,ll n) { ll temp=(n-1)/x; return temp*x+(temp*(temp-1)/2)*x; } int main() { ll t,n,m; int kase=1; scanf("%lld",&t); while(t--) { set<ll> s; scanf("%lld%lld",&n,&m); for(int i=0;i<n;i++) { ll x; scanf("%lld",&x); s.insert(gcd(x,m)); } vector<ll> g; for(auto it:s) { int flag=1; for(auto itt:s) if(it%itt==0&&it!=itt) flag=0; if(flag)g.pb(it); } ll cnt=g.size(); ll ans=0; for(ll i=0; i<(1ll<<cnt); i++) { ll temp=1,jishu=0; for(ll j=0; j<cnt; j++) { if(i&(1<<j)) temp=temp*g[j]/gcd(g[j],temp),jishu++; } if(jishu==0) continue; if(jishu%2==1) ans+=sum(temp,m); else ans-=sum(temp,m); } printf("Case #%d: %lld\n",kase++,ans); } }
标签:lin 原理 multiple res 暴力 i++ 应该 href can
原文地址:https://www.cnblogs.com/stranger-/p/9794848.html