当前位置: 代码迷 >> 综合 >> hdu5726 GCD+ST表 by:lethalboy
  详细解决方案

hdu5726 GCD+ST表 by:lethalboy

热度:85   发布时间:2023-09-30 17:56:07.0

@ hdu 5726  

ST表+gcd()

数据大,不能暴力求,用线段树会超时,我们可以利用ST表求区间gcd;

至于第二问,对于以ai开头的区间来说,gcd随区间长度单调递减,藉此可在nlogn时间内利用二分求出每个gcd值出现次数,用map或hash存储即可

代码附下:

#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<cstring> #include<map> using namespace std; typedef long long ll;
ll logs[111111];
ll n,q,t;
ll x,y;
ll cnt;
ll f[111111][20]; inline ll gcd(ll a,ll b) {
     return b==0?a:gcd(b,a%b);}
ll query(ll x,ll y) {
     ll len=logs[y-x+1];return gcd(f[x][len],f[y-(1<<len)+1][len]); }
ll solve(ll a,ll tmp) {
     ll ans=-1,ret=0,now;ll l=a,r=n;while(l<=r){
     ll mid=(l+r)>>1;now=query(a,mid);if(now>tmp)l=mid+1;if(now<=tmp)r=mid-1;if(now==tmp)ans=mid;}if(ans!=-1)now=query(a,ans);else now=-1;while(now==tmp&&ans<=n){
     ret++;ans++;now=query(a,ans);}return ret; } int main() {
     for(ll i=1; i<=100000; ++i)logs[i]=log2(i)+1e-6;scanf("%lld",&t); for(ll u=1;u<=t;u++) {
     scanf("%lld",&n,&q);for(ll i=1;i<=n;i++)scanf("%lld",&f[i][0]);for(ll i=1;i<17;i++)for(ll k=1;k<=n;k++){
     if(k+(1<<i)-1>n) continue;f[k][i]=gcd(f[k][i-1],f[k+(1<<(i-1))][i-1]);}map<ll,ll> rec;for(ll i=1; i<=n; ++i){
     ll g=f[i][0],j=i;while(j<=n){
     ll l=j,r=n;while(l<r){
     ll mid=l+r+1>>1;if(query(i,mid)==g) l=mid;else r=mid-1;}rec[g]+=(l-j+1);j=l+1;g=query(i,j);}}printf("Case #%d:\n",u);scanf("%lld",&q);for(ll i=1;i<=q;i++){
     scanf("%lld%lld",&x,&y);cnt=0;ll tmp=query(x,y);printf("%lld %lld\n",tmp,rec[tmp]);} } return 0; }