leetcode 3117. 划分数组得到最小的值之和(线段树、dp、二分)

3117. 划分数组得到最小的值之和 - 力扣(LeetCode)

思路

对于这种划分区间段的问题,通常我们可以先考虑dp,dp[i][j]表示第i个num数作为第j段最后一个元素得到的前j段的最小和。用二分去查找合法区间的左右端点,因为m最大为10,考虑使用10颗线段树(用RMQ也可以)去维护区间最小值。代码有点丑陋。

  1 #define IO std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  2 #define bug(x) cout<<#x<<" is "<<x<<endl
  3 #include <bits/stdc++.h>
  4 #define iter ::iterator
  5 using namespace  std;
  6 typedef long long ll;
  7 typedef pair<int,int>P;
  8 #define pb push_back
  9 #define mk make_pair
 10 #define se second
 11 #define fi first
 12 #define rs o*2+1
 13 #define ls o*2
 14 int mx[11][40005];
 15 int a[10005][20],b[11][20],d[10005][11];
 16 
 17 class Solution {
 18 public:
 19     void init(){
 20         for(int i=1;i<=10;i++){
 21             for(int j=1;j<=40000;j++)mx[i][j]=1e9;
 22         }
 23         for(int i=0;i<20;i++){
 24             for(int j=1;j<=10000;j++){
 25                 a[j][i]=0;
 26                 if(j<=10)b[j][i]=0;
 27             }
 28         }
 29         for(int i=0;i<=10000;i++){
 30             for(int j=0;j<=10;j++)d[i][j]=0;
 31         }
 32     }
 33     void up(int o,int k,int l,int r,int pos,int val){
 34         if(l==r){
 35             mx[k][o]=val;
 36             return;
 37         }
 38         int m=(l+r)/2;
 39         if(pos<=m)up(ls,k,l,m,pos,val);
 40         else up(rs,k,m+1,r,pos,val);
 41         mx[k][o]=min(mx[k][o],min(mx[k][ls],mx[k][rs]));
 42     }
 43 
 44     int qu(int o,int k,int l,int r,int ql,int qr){
 45         if(l>=ql&&r<=qr)return mx[k][o];
 46         int res=1e9;
 47         int m=(l+r)/2;
 48         if(ql<=m)res=qu(ls,k,l,m,ql,qr);
 49         if(qr>m)res=min(res,qu(rs,k,m+1,r,ql,qr));
 50         return res;
 51     }
 52     void gao(int id,int x){
 53         int cnt=0;
 54         for(int i=0;i<=17;i++)a[id][i]=a[id-1][i];
 55         while(x){
 56             if(x&1)a[id][cnt]=a[id-1][cnt]+1;
 57             x>>=1;
 58             cnt++;
 59         }
 60     }
 61     int check(int k,int id,int pre){
 62         for(int i=0;i<=17;i++){
 63             if(b[k][i]){
 64                 if(a[id][i]-a[pre-1][i]!=id-pre+1)return 0;
 65             }
 66         }
 67         return 1;
 68     }
 69 
 70     int check1(int k,int id,int pre){
 71         for(int i=0;i<=17;i++){
 72             if(!b[k][i]){
 73                 //ug(i);
 74                 if(k>1){
 75                     if(a[id][i]-a[pre][i]==id-pre)return 0;
 76                 }
 77                 else if(a[id][i]-a[pre-1][i]==id-pre+1)return 0;
 78             }
 79         }
 80         return 1;
 81     }
 82     int minimumValueSum(vector<int>& nums, vector<int>& andValues) {
 83         init();
 84         int n=nums.size();
 85         int m=andValues.size();
 86         for(int i=0;i<n;i++){
 87             gao(i+1,nums[i]);
 88         }
 89         for(int i=0;i<m;i++){
 90             int x=andValues[i];
 91             int cnt=0;
 92             while(x){
 93                 if(x&1)b[i+1][cnt]=1;
 94                 x>>=1;
 95                 cnt++;
 96             }
 97         }
 98         for(int i=1;i<=m;i++){
 99             for(int j=1;j<=n;j++){
100                 int l=1,r=j;
101                 int id=-1;
102                 while(l<r){                 
103                     int m=(l+r)/2;
104                     if(check(i,j,m)){
105                         r=m;
106                         id=m;
107                     }
108                     else l=m+1;
109                 }
110                 if(check(i,j,l))id=l;
111                 if(i>1&&id>1)id--;
112                 if(id<=0)continue;
113                 int id1=-1;
114                 l=1,r=j;
115                 while(l<r){
116                     int m=(l+r)/2;
117                     if(check1(i,j,m)){
118                         l=m+1;
119                         id1=m;
120                     }
121                     else r=m;
122                 }
123                 if(check1(i,j,l))id1=l;
124                 if(id1<id)continue;
125                 if(id1>=j&&i>1)id1=j-1;
126                 if(id>id1)continue;
127                 //printf("%d %d %d %d\n",j,i,id,id1);
128                 int res=qu(1,i-1,1,n,id,id1);
129                 if(i==1){
130                     if(!check(1,j,1)||!check(1,j,1))continue;
131                     d[j][i]=nums[j-1];
132                     //printf("%d %d %d\n",j,i,d[j][i]);
133                     up(1,i,1,n,j,d[j][i]);
134                     continue;
135                 }
136                 if(res==1e9)continue;
137                 d[j][i]=res+nums[j-1];
138                 //printf("%d %d %d %d %d %d\n",j,i,res,d[j][i],id,id1);
139                 up(1,i,1,n,j,d[j][i]);         
140             }
141         }
142         if(d[n][m]==0)d[n][m]=-1;
143         return d[n][m];
144     }
145 };
146 
147 int main(){
148     vector<int>nums={22, 24, 22, 3, 19, 12, 21, 10, 10, 23, 25, 1, 10, 12, 3, 25, 18, 15, 19, 2, 22, 22, 19, 25};
149     vector<int>andValues={25};
150     int res=22;
151     for(int i=1;i<24;i++){
152         res=(res&nums[i]);
153         bug(res);
154     }
155     //bug(res);
156 
157     // vector<int>nums={2,3,5,7,7,7,5};
158     // vector<int>andValues={0,7,5};
159 
160     // vector<int>nums={4,8,2,9};
161     // vector<int>andValues={0,0};
162     //bug(nums.size());
163     Solution A;
164     cout<<A.minimumValueSum(nums,andValues)<<endl;
165 }

 

 
 
posted @ 2024-05-25 00:09  Venux  阅读(19)  评论(0编辑  收藏  举报