hdu5320

好久没写题代码能力简直贫弱

这道题思路不难,写起来有点麻烦

首先以某个点为右端点的区间的gcd种类级别是log的(因为下降最少是除2)

预处理所有的四元组(g,l,r,x)表示以x为右端点,左端点在[l,r]内区间公约数都是g

然后以g为第一关键字,x为第二关键字即可

最多选取不相邻区间数dp+线段树

计算方案要考虑两种情况,dp[i]=dp[j]+1

一是j落在[l,r-1],二是j落在[1,l-1],这两种i选取的方案是不一样的

然后就没了

  1 #include<bits/stdc++.h>
  2 #define mp make_pair
  3 #define fi first
  4 #define se second
  5 #define pi pair<int,int>
  6 using namespace std;
  7 typedef long long ll;
  8 const int mo=998244353;
  9 struct node{int w,l,r,x;} q[100010*30];
 10 struct po{int a,b,c;} mx[100010*4],null;
 11 pi g[2][100010];
 12 int st[100010*4],a[100010],n,t,tt,b[5],cas,ans1,ans2;
 13 bool v[100010*4];
 14
 15 int gcd(int a,int b)
 16 {
 17     return (b==0)?a:gcd(b,a%b);
 18 }
 19
 20 void inc(int &a,int b)
 21 {
 22     a+=b;
 23     if (a>mo) a-=mo;
 24 }
 25
 26 bool cmp(node a,node b)
 27 {
 28     if (a.w==b.w) return a.x<b.x;
 29     return a.w<b.w;
 30 }
 31
 32 void init()
 33 {
 34     int p=0;
 35     q[1]=(node){a[1],1,1,1};
 36     b[0]=1;
 37     g[0][1]=mp(1,a[1]);
 38     for (int i=2; i<=n; i++)
 39     {
 40         p^=1; b[p]=1; g[p][1]=mp(i,a[i]);
 41         int gg=a[i];
 42         for (int j=1; j<=b[p^1]; j++)
 43         {
 44             pi tmp=g[p^1][j];
 45             gg=gcd(tmp.se,gg);
 46             if (g[p][b[p]].se==gg) g[p][b[p]].fi=tmp.fi;
 47             else g[p][++b[p]]=mp(tmp.fi,gg);
 48         }
 49         q[++t]=(node){g[p][1].se,g[p][1].fi,i,i};
 50         for (int j=2; j<=b[p]; j++)
 51             q[++t]=(node){g[p][j].se,g[p][j].fi,g[p][j-1].fi-1,i};
 52     }
 53     sort(q+1,q+1+t,cmp);
 54 }
 55
 56 void up(po &a,po b,po c)
 57 {
 58     if (b.a>c.a) a=b;
 59     else {
 60         a=c;
 61         if (b.a==c.a)
 62         {
 63             inc(a.b,b.b);
 64             inc(a.c,b.c);
 65         }
 66     }
 67 }
 68
 69 po ask(int i,int l,int r,int x,int y)
 70 {
 71     if (y<x||x<1) return null;
 72     if (x<=l&&y>=r) return mx[i];
 73     int m=(l+r)>>1;
 74     po c;
 75     if (x<=m&&y<=m) return ask(i*2,l,m,x,y);
 76     else if (y>m&&x>m) return ask(i*2+1,m+1,r,x,y);
 77     else {
 78         up(c,ask(i*2,l,m,x,y),ask(i*2+1,m+1,r,x,y));
 79         return c;
 80     }
 81 }
 82
 83 void add(int i,int l,int r,int f1,int f2,int x)
 84 {
 85     if (!v[i])
 86     {
 87         st[++tt]=i;
 88         v[i]=1;
 89     }
 90     if (l==r)
 91     {
 92         mx[i]=(po){f1,f2,(ll)l*f2%mo};
 93         return;
 94     }
 95     int m=(l+r)>>1;
 96     if (x<=m) add(i*2,l,m,f1,f2,x);
 97     else add(i*2+1,m+1,r,f1,f2,x);
 98     up(mx[i],mx[i*2],mx[i*2+1]);
 99 }
100
101 void work(int l,int r)
102 {
103     tt=0;
104     if (ans1>r-l+1) return;
105     add(1,1,n,1,q[l].r-q[l].l+1,q[l].x);
106     int s1=1,s2=q[l].r-q[l].l+1;
107     for (int i=l+1; i<=r; i++)
108     {
109         int f1,f2;
110         po m1=ask(1,1,n,1,q[i].l-1);
111         po m2=ask(1,1,n,q[i].l,q[i].r-1);
112         if (!m1.a&&!m2.a)
113         {
114             f1=1;
115             f2=q[i].r-q[i].l+1;
116         }
117         else if (m1.a>m2.a)
118         {
119             f1=m1.a+1;
120             f2=(ll)(q[i].r-q[i].l+1)*m1.b%mo;
121         }
122         else {
123             f1=m2.a+1;
124             f2=(1ll*q[i].r*m2.b%mo-m2.c+mo)%mo;
125             if (m1.a==m2.a) inc(f2,(ll)(q[i].r-q[i].l+1)*m1.b%mo);
126         }
127         if (s1<f1)
128         {
129             s1=f1;
130             s2=f2;
131         }
132         else if (s1==f1) inc(s2,f2);
133         add(1,1,n,f1,f2,q[i].x);
134     }
135     for (int i=1; i<=tt; i++)
136     {
137         int x=st[i];
138         mx[x]=null;
139         v[x]=0;
140     }
141     if (s1>ans1) {ans1=s1; ans2=s2;}
142     else if (s1==ans1) inc(ans2,s2);
143 }
144
145 void build(int i,int l,int r)
146 {
147     mx[i]=null;
148     if (l!=r)
149     {
150         int m=(l+r)>>1;
151         build(i*2,l,m);
152         build(i*2+1,m+1,r);
153     }
154 }
155
156 int main()
157 {
158     null=(po){0,0,0};
159     build(1,1,100000);
160     memset(v,0,sizeof(v));
161     while (scanf("%d",&n)!=EOF)
162     {
163         for (int i=1; i<=n; i++) scanf("%d",&a[i]);
164         t=1; init();
165         int i=1; ans1=0; ans2=0;
166         tt=0;
167         while (i<=t)
168         {
169             int j=i+1;
170             while (j<=t&&q[j].w==q[i].w) j++;
171             work(i,j-1);
172             i=j;
173         }
174         printf("%d %d\n",ans1,ans2);
175     }
176 }

时间: 2024-12-28 09:34:49

hdu5320的相关文章

HDU5320 : Fan Li

考虑枚举左端点i,则随着右端点的右移,一共只有$O(\log n)$种不同的gcd取值.所以首先通过ST表+二分查找预处理出$O(n\log n)$个四元组(x,i,l,r),表示左端点为i,右端点取值范围在[l,r]内,且这一段的gcd都为x. 将四元组按照x为第一关键字,i为第二关键字排序,对于相同的x一起处理. 当x相同时,显然所有的i互不相同.设f[i]为恰好以位置i为结尾的最优解,则对于一个四元组(x,i,l,r),能更新它的最优解为区间[1,i-1]的最优值+1,然后用它更新区间[l