标签:nta mit continue flag back cassert 个数 double ios
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 4904 Accepted Submission(s): 1631
题意就是跳青蛙,通过分析会发现,就是步数a[i]与石头数m,通过gcd(a[i],m)之后,gcd的倍数的和。
因为重复的数只计算一次,所以要去重。
一开始想的是容斥去重,然而还是太捞了,。。。
这道题和队友讨论了3天,还问了学长,发现几个问题:
(1)如果直接枚举gcd的遍历,应该为去重他们的最小公倍数,也就是这样的。
for(ll j=0;j<cnt;j++) { if(i&(1<<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(欧拉函数):
1 //欧拉函数的公式求解 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<bitset> 7 #include<cassert> 8 #include<cctype> 9 #include<cmath> 10 #include<cstdlib> 11 #include<ctime> 12 #include<deque> 13 #include<iomanip> 14 #include<list> 15 #include<map> 16 #include<queue> 17 #include<set> 18 #include<stack> 19 #include<vector> 20 using namespace std; 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 24 const double PI=acos(-1.0); 25 const double eps=1e-6; 26 const ll mod=1e9+7; 27 const int inf=0x3f3f3f3f; 28 const int maxn=1e5+10; 29 const int maxm=100+10; 30 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 31 32 ll a[maxn],n,m; 33 34 ll gcd(ll a,ll b) 35 { 36 return b==0?a:gcd(b,a%b); 37 } 38 39 ll euler(ll n) 40 { 41 ll ans=n; 42 for(int i=2;i*i<=n;i++){ 43 if(n%i==0){ 44 ans=ans/i*(i-1); 45 while(n%i==0) n/=i; 46 } 47 } 48 if(n>1) ans=ans/n*(n-1); 49 return ans; 50 } 51 52 bool solve(int x) 53 { 54 for(int i=0;i<n;i++){ 55 if(x%a[i]==0) return true; 56 } 57 return false; 58 } 59 60 int main() 61 { 62 int t; 63 scanf("%d",&t); 64 for(int cas=1;cas<=t;cas++){ 65 memset(a,0,sizeof(a)); 66 scanf("%lld%lld",&n,&m); 67 for(int i=0;i<n;i++){ 68 scanf("%d",a+i); 69 a[i]=gcd(a[i],m); 70 } 71 ll ans=0; 72 for(int i=1;i*i<=m;i++){ 73 if(m%i) continue; 74 if(solve(i)) ans+=(ll)euler(m/i)*m/2; 75 if(i*i==m||i==1) continue; 76 if(solve((m/i))) ans+=(ll)euler(i)*m/2; 77 } 78 printf("Case #%d: %lld\n",cas,ans); 79 } 80 }
代码2(容斥原理):
1 //容斥定理 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<bitset> 7 #include<cassert> 8 #include<cctype> 9 #include<cmath> 10 #include<cstdlib> 11 #include<ctime> 12 #include<deque> 13 #include<iomanip> 14 #include<list> 15 #include<map> 16 #include<queue> 17 #include<set> 18 #include<stack> 19 #include<vector> 20 using namespace std; 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 24 const double PI=acos(-1.0); 25 const double eps=1e-6; 26 const ll mod=1e9+7; 27 const int inf=0x3f3f3f3f; 28 const int maxn=1e5+10; 29 const int maxm=100+10; 30 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 31 32 ll gcd(ll a,ll b) 33 { 34 return b==0?a:gcd(b,a%b); 35 } 36 37 ll g[maxn],fac[maxn]; 38 int tp[maxn],num[maxn],vis[maxn]; 39 40 int main() 41 { 42 int t; 43 scanf("%d",&t); 44 for(int cas=1;cas<=t;cas++){ 45 ll n,m; 46 scanf("%lld%lld",&n,&m); 47 int ok=0; 48 for(int i=0;i<n;i++){ 49 scanf("%lld",&g[i]); 50 g[i]=gcd(g[i],m); 51 if(g[i]==1) ok=1; 52 } 53 if(ok==1){ 54 printf("Case #%d: %lld\n",cas,m*(m-1)/2); 55 continue; 56 } 57 sort(g,g+n); 58 n=unique(g,g+n)-g; 59 memset(vis,0,sizeof(vis)); 60 memset(num,0,sizeof(num)); 61 int cnt=0; 62 for(ll i=2;i*i<=m;i++){ 63 if(i*i==m) fac[cnt++]=m/i; 64 else if(m%i==0) fac[cnt++]=i,fac[cnt++]=m/i; 65 } 66 sort(fac,fac+cnt); 67 int cnt1=0; 68 for(int i=0;i<n;i++){ 69 if(!vis[i]){ 70 tp[cnt1++]=g[i]; 71 for(int j=0;j<n;j++) 72 if(g[j]%g[i]==0) vis[j]=1; 73 } 74 } 75 memset(vis,0,sizeof(vis)); 76 for(int i=0;i<cnt;i++){ 77 for(int j=0;j<cnt1;j++){ 78 if(fac[i]%tp[j]==0){ 79 vis[i]=1; 80 break; 81 } 82 } 83 } 84 ll sum=0; 85 for(int i=0;i<cnt;i++){ 86 if(num[i]!=vis[i]){ 87 sum+=m*(m/fac[i]-1)/2*(vis[i]-num[i]); 88 for(int j=i+1;j<cnt;j++) 89 if(fac[j]%fac[i]==0) 90 num[j]=num[j]+vis[i]-num[i]; 91 } 92 } 93 printf("Case #%d: %lld\n",cas,sum); 94 } 95 return 0; 96 }
贴一下我们想了3天的错误代码,纪念一下。
代码(错误的):
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<bitset> 6 #include<cassert> 7 #include<cctype> 8 #include<cmath> 9 #include<cstdlib> 10 #include<ctime> 11 #include<deque> 12 #include<iomanip> 13 #include<list> 14 #include<map> 15 #include<queue> 16 #include<set> 17 #include<stack> 18 #include<vector> 19 using namespace std; 20 typedef long long ll; 21 typedef pair<int,int> pii; 22 23 const double PI=acos(-1.0); 24 const double eps=1e-6; 25 const ll mod=1e9+7; 26 const int inf=0x3f3f3f3f; 27 const int maxn=1e5+10; 28 const int maxm=100+10; 29 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 30 #define lson l,m,rt<<1 31 #define rson m+1,r,rt<<1|1 32 33 ll gcd(ll a,ll b) 34 { 35 return b?gcd(b,a%b):a; 36 } 37 38 ll sum(ll x,ll n) 39 { 40 ll temp=(n-1)/x; 41 return temp*x+(temp*(temp-1)/2)*x; 42 } 43 44 ll a[maxn]; 45 46 int main() 47 { 48 ll t; 49 scanf("%lld",&t); 50 for(int cas=1;cas<=t;cas++) 51 { 52 ll n,m; 53 scanf("%lld%lld",&n,&m); 54 ll h=0; 55 for(int i=0;i<n;i++) 56 { 57 ll x; 58 scanf("%lld",&x); 59 a[h++]=gcd(x,m); 60 } 61 vector<ll> g; 62 sort(a,a+h); 63 for(int i=h-1;i>=0;i--){ 64 int flag=0; 65 for(int j=i-1;j>=0;j--){ 66 if(a[i]%a[j]==0) flag=1; 67 } 68 if(!flag) g.push_back(a[i]); 69 } 70 int cnt=g.size(); 71 ll ans=0; 72 for(ll i=0;i<(1ll<<cnt);i++) 73 { 74 ll temp=1,jishu=0; 75 for(ll j=0;j<cnt;j++) 76 { 77 if(i&(1<<j)) 78 temp=temp*g[j]/gcd(temp,g[i]),jishu++; 79 } 80 if(jishu==0)continue; 81 if(jishu&1) ans+=sum(temp,m); 82 else ans-=sum(temp,m); 83 } 84 printf("Case #%d: %lld\n",cas,ans); 85 } 86 }
到此为止,拜拜,再也不看这个题了。
标签:nta mit continue flag back cassert 个数 double ios
原文地址:https://www.cnblogs.com/ZERO-/p/9813643.html