标签:.com i+1 while names 价值 eof app class end
这题其实比较naive……
问题是我更naive……
这题伟大的杨队长提出了一个 的dp做法……
我的做法就很naive了。
首先我们发现,如果我们对两个相邻的数进行一次操作,这个操作产生的影响最多波及的a[i+2]
(前提是我们从前向后操作)
这就为我们分类讨论提供了简化。
其次有一个很显然的结论:
设a[i],a[i+1]的gcd为x,显然我选择每次除掉x的一个质因数,至少比直接除掉x的策略要优
这个结论很显然,当且仅当两个质因数都是2的时候这两种操作的价值才相等。
或者只有一个质因数。
换而言之我们先筛出素数,然后计算每个质数产生的贡献,讨论它所能够影响的范围即可。
然后这么做发现我能被自己叉掉……
于是在这么跑完之后,再扫一次gcd数组,继续上述的讨论直接除掉gcd即可~
因为可能会剩下某些质数……
#include<bits/stdc++.h> #define N 50005 using namespace std; typedef long long ll; int n,a[N],g[N],f[N],vis[N],cnt; ll ans,sum; int gcd(int x,int y){if(!y)return x;return gcd(y,x%y);} inline int read(){ int f=1,x=0;char ch; do{ch=getchar();if(ch==‘-‘)f=-1;}while(ch<‘0‘||ch>‘9‘); do{x=x*10+ch-‘0‘;ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘); return f*x; } int prime[N]; void calcpri(){ memset(vis,1,sizeof(vis)); for(int i=2;i<=5000;i++){ if(vis[i])prime[++cnt]=i; for(int j=1;j<=cnt;j++){ int t=i*prime[j];if(t>5000)break; vis[t]=0; if(i%prime[j]==0)break; } } } int main(){ n=read();for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<n;i++)g[i]=gcd(a[i],a[i+1]); calcpri(); for(int i=1;i<=cnt;i++){ memset(f,0,sizeof(f)); for(int j=1;j<n;j++)while(g[j]%prime[i]==0)f[j]++,g[j]/=prime[i]; sum=0; for(int j=1;j<n;j++){ sum+=f[j];int w=f[j];f[j]=0; w=min(w,f[j+1]);f[j+1]-=w; w=min(w,f[j+2]);f[j+2]-=w; } ans+=1LL*prime[i]*sum; } for(int i=1;i<n;i++){ if(g[i]>1){ ans+=g[i];if(g[i+2]==g[i]&&g[i+1]==g[i])g[i+2]=1; if(g[i+1]==g[i])g[i+1]=1;g[i]=1; } } cout<<ans<<endl; }
标签:.com i+1 while names 价值 eof app class end
原文地址:http://www.cnblogs.com/zcysky/p/7064059.html