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 }