Codeforces1699E Three Days Grace【数学】【DP】

分析:

一开始觉得是二分答案,发现行不通之后改为枚举最小值。

现在我将这若干个数分解,假设分解完之后得到的最小值为$i$,那么我就是要在最小值为$i$的基础上尽量最小化分解的各数的最大值。

考虑DP:设$f[x][i]$表示在分解结果最小值大于等于$i$的情况下,将$x$分解得到的最大值最小是多少。可以得到如下转移:

$$f[x][i] = min(f[\frac{x}{i}][i],f[x][i+1])\quad where\ i\ is\ a\ factor\ of\ x$$

或者

$$f[x][i] = f[x][i+1]\quad i\ is\ not\ x's\ factor$$

注意到这样转移状态数太多了,但是我们发现,只有当$i$是$x$的因子时,$f[x][i]$的值才会发生变化,所以转移可以进一步优化,只留$n\ln n$个有用的状态。

接着,答案就是对每个枚举的$i$,求$f[a[x]][i]$的最大值即可。

这个求最大值的过程如果倒着用可删堆维护会爆空间,所以考虑正着来。先倒着预处理出来$i$等于多少时,$f[x][i]$会发生变化就行了。(参考我代码里的update部分)

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = 1050000;
 5 const int maxm = 5050000;
 6 
 7 int n,m;
 8 int a[maxn];
 9 int suf[maxm];
10 int tab[maxm];
11 int update[maxm];
12 
13 struct Priority_Queue{
14     priority_queue<int,vector<int>,less<int> > pq,del;
15     void Push(int now){pq.push(now);}
16     void Del(int now){del.push(now);}
17     int Top(){
18     while(!del.empty() && pq.top() == del.top()){
19         pq.pop();
20         del.pop();
21     }
22     return pq.top();
23     }
24     void clear(){
25     while(!pq.empty()) pq.pop();
26     while(!del.empty()) del.pop();
27     }
28 }Q;
29 
30 int main(){
31     int t; scanf("%d",&t);
32     while(t--){
33     scanf("%d%d",&n,&m);
34     int minn = 1e9,maxx = 0;
35     Q.clear();
36     for(int i=1;i<=n;i++) {
37         scanf("%d",&a[i]);
38         minn = min(minn,a[i]);
39         maxx = max(maxx,a[i]);
40     }
41     for(int i=1;i<=maxx;i++){
42         suf[i] = i;
43         tab[i] = 0;
44         update[i] = 0;
45     }
46     for(int i=1;i<=n;i++) tab[a[i]]=1;
47     int ans = 1e9;
48     for(int i=maxx;i>=2;i--){
49         for(int j=i;1ll*j*i<=maxx;j++){
50         if(tab[i*j]) update[i+1] = max(update[i+1],suf[i*j]);
51         suf[i*j] = min(suf[i*j],suf[j]);
52         }
53     }
54     for(int i=1;i<=maxx;i++){
55         if(tab[i]){
56         update[1] = max(update[1],suf[i]);
57         }
58     }
59     int tot = 0;
60     for(int i=1;i<=minn;i++){
61         tot = max(tot,update[i]);
62         ans = min(ans,tot-i);
63     }
64     printf("%d\n",ans);
65     }
66 }

 

posted @ 2022-08-16 14:22  menhera  阅读(33)  评论(0编辑  收藏  举报