Educational Codeforces Round 80 (Rated for Div. 2) 二分 + 状压
傳送門
文章目錄
- 題意:
- 思路:
題意:
給你nnn個長度為mmm的數組,選出兩個來,讓他們每一位取maxmaxmax構成新數組bbb,讓后最大化bbb的最小值。
思路:
看到m=8m=8m=8,也就是每個數組長度為mmm,很容易想到狀壓。由于要最大化最小值,我們不妨二分這個最小值,讓后將nnn個數組狀壓成一個二進制,>=mid>=mid>=mid的位置為111,否則為000。這個時候我們只需要找出兩個數使其取或后[0,m?1][0,m-1][0,m?1]的每一位都是111即可。
我們發現只需要記錄一下當前狀態對應的編號,讓后28?282^{8}*2^{8}28?28枚舉狀態,讓后判斷(i∣j)==(1<<m)?1(i|j)==(1<<m)-1(i∣j)==(1<<m)?1即可。
復雜度O(max(nm,22m)?log(1e9))O(max(nm,2^{2m})*log(1e9))O(max(nm,22m)?log(1e9))
如果mmm很大怎么辦?有沒有更好的方法呢?當然是有的。
假設我們知道了狀態110101110101110101,那么我們只需要看一下是否存在001010001010001010即可。而這個狀態有可能是某個狀態的子集,我們不能對于每數都將其子集暴力的加入,這樣復雜度會爆掉的,看到大佬有一個好的方法來遞推求子集。我們從(1<<m)?1(1<<m)-1(1<<m)?1開始,記為nownownow,讓后遍歷[0,m?1][0,m-1][0,m?1],記為jjj,看一下now∣(1<<j)now|(1<<j)now∣(1<<j)是否存在,存在的話就說明他是now∣(1<<j)now|(1<<j)now∣(1<<j)的一個子集,就直接繼承now∣(1<<j)now|(1<<j)now∣(1<<j)的信息即可。這樣遞推的復雜度為2m?m2^m*m2m?m,顯然更加的優秀。
復雜度O(max(nm,2m?m)?log(1e9))O(max(nm,2^{m}*m)*log(1e9))O(max(nm,2m?m)?log(1e9))
//#pragma GCC optimize(2) #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<map> #include<cmath> #include<cctype> #include<vector> #include<set> #include<queue> #include<algorithm> #include<sstream> #include<ctime> #include<cstdlib> #define X first #define Y second #define L (u<<1) #define R (u<<1|1) #define pb push_back #define mk make_pair #define Mid (tr[u].l+tr[u].r>>1) #define Len(u) (tr[u].r-tr[u].l+1) #define random(a,b) ((a)+rand()%((b)-(a)+1)) #define db puts("---") using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); } //void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); } //void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII;const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f; const double eps=1e-6;int n,m; int a[N][10]; int id[1010],ans1,ans2; bool flag;bool check(int mid) {memset(id,0,sizeof(id));for(int i=0;i<n;i++){int now=0;for(int j=0;j<m;j++)if(a[i][j]>=mid) now+=(1<<j);id[now]=i+1;}int tot=(1<<m);for(int i=tot-1;i>=0;i--)for(int j=0;j<m;j++)if(id[i|(1<<j)])id[i]=id[i|(1<<j)];for(int i=tot-1;i>=0;i--)if(id[i]&&id[i^(tot-1)]){ans1=id[i];ans2=id[i^(tot-1)];return true;}return false; }int main() { // ios::sync_with_stdio(false); // cin.tie(0);scanf("%d%d",&n,&m);for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%d",&a[i][j]);int l=0,r=1e9,ans;while(l<=r){int mid=l+r>>1;if(check(mid)) l=mid+1;else r=mid-1;}printf("%d %d\n",ans1,ans2);return 0; } /**/復雜度O(max(nm,22m)?log(1e9))O(max(nm,2^{2m})*log(1e9))O(max(nm,22m)?log(1e9))
//#pragma GCC optimize(2) #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<map> #include<cmath> #include<cctype> #include<vector> #include<set> #include<queue> #include<algorithm> #include<sstream> #include<ctime> #include<cstdlib> #define X first #define Y second #define L (u<<1) #define R (u<<1|1) #define pb push_back #define mk make_pair #define Mid (tr[u].l+tr[u].r>>1) #define Len(u) (tr[u].r-tr[u].l+1) #define random(a,b) ((a)+rand()%((b)-(a)+1)) #define db puts("---") using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); } //void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); } //void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII;const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f; const double eps=1e-6;int n,m; int a[N][10]; int id[1010],ans1,ans2; bool flag;bool check(int mid) {memset(id,0,sizeof(id));for(int i=0;i<n;i++){int now=0;for(int j=0;j<m;j++)if(a[i][j]>=mid) now+=(1<<j);id[now]=i+1;}for(int i=0;i<(1<<m);i++)for(int j=0;j<(1<<m);j++)if(id[i]&&id[j]&&(i|j)==((1<<m)-1)){ans1=id[i],ans2=id[j];return true;}return false; }int main() { // ios::sync_with_stdio(false); // cin.tie(0);scanf("%d%d",&n,&m);for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%d",&a[i][j]);int l=0,r=1e9,ans;while(l<=r){int mid=l+r>>1;if(check(mid)) l=mid+1;else r=mid-1;}printf("%d %d\n",ans1,ans2);return 0; } /**/總結
以上是生活随笔為你收集整理的Educational Codeforces Round 80 (Rated for Div. 2) 二分 + 状压的全部內容,希望文章能夠幫你解決所遇到的問題。