A了三题,rk1000左右应该可以上分啦,开??。
后面的D,E比赛时就感觉可做,但又想不到方法。
然后我补了下,确实如此。
题意:很简单,给一个矩阵,找两行序列i,j,使得通过每个元素取当列最大合成出来的序列,最小值最大。
hit 1:比赛里我是真的有想二分,最小值最大,这不是经典二分答案套路嘛。
hit 2:比赛里我也是真的有注意到这个m <=8 给的很小,想以此为突破点干点啥?
然后要么太晚了,要么我做了三题自满了,总之没想到最终解法就睡觉了。
其实把二者结合起来,就可以A了这题了。一定注意 如果给的某个数字很小的话,可以二进制转化 。
也就是bitmask,英文好帅。
然后就二分答案,check的时候,对每个序列按是否大于等于你目标值转化成一个二进制串,再找有没有另一个二进制串满足两者通过 按位或 | 起来 得到一个完整的全部满足的全为1的串。
就没了。
贴个代码
1 #include <bits/stdc++.h> 2 #ifndef ONLINE_JUDGE 3 #define debug(x) cout << #x << ": " << x << endl 4 #else 5 #define debug(x) 6 #endif 7 using namespace std; 8 typedef long long ll; 9 const int MAXN=3e5+7; 10 const int INF=0x3f3f3f3f; 11 const int MOD=1e9+7; 12 13 int a[MAXN][10],vis[300]; 14 int ans1,ans2,n,m; 15 16 bool check(int x) 17 { 18 for(int i=0;i<(1<<m);++i) vis[i]=0; 19 for(int i=1;i<=n;++i) 20 { 21 int k=0; 22 for(int j=0;j<m;++j) 23 { 24 k+=(a[i][j]>=x)*(1<<j); 25 } 26 vis[k]=i; 27 } 28 for(int i=0;i<(1<<m);++i) 29 { 30 if(!vis[i]) continue; 31 for(int j=0;j<(1<<m);++j) 32 { 33 if(!vis[j]) continue; 34 if((i|j)==(1<<m)-1) 35 { 36 ans1=vis[i],ans2=vis[j]; 37 return true; 38 } 39 } 40 } 41 return false; 42 } 43 44 int main() 45 { 46 ios::sync_with_stdio(false); 47 cin.tie(0); 48 cin>>n>>m; 49 for(int i=1;i<=n;++i) 50 for(int j=0;j<m;++j) 51 cin>>a[i][j]; 52 int l=0,r=INF; 53 while(l<=r) 54 { 55 int mid=l+r>>1; 56 if(check(mid)) l=mid+1; 57 else r=mid-1; 58 } 59 cout<<ans1<<‘ ‘<<ans2<<endl; 60 return 0; 61 }
题意:也非常的清晰明了,感觉以前在CF上也见过类似的,不过比这题简单的。就打电话,谁打了就把这个数提到前面。求每个数出现的最小和最大位置。
比赛时,我D想不出,看了眼E,真的有想树状数组维护,但主要我不知道咋移,啥时候哪个位置+1,-1。
然后发现看别人的程序基本就是正解。所以自己算法的思想大致还是到位的,但细部想不出呀。
这题思维的闪光点,主要就是开始时每个元素目前所在pos的设置,设置为i+m,就是预留了m个位置,给询问序列中的m个元素来移动,给开始n个元素的位置设置成虚点!
反正我第一次做是想不到。
别的都很好想,就是对每个询问,也就是给出的序列中给的值,动态的更新位置,并更新最大值,注意新位置应该是从m开始往前,也就是m~1。
树状数组的ask就是询问前缀和,也就是该元素当前处于第几个,也就是他的位置。
贴个代码
1 #include <bits/stdc++.h> 2 #ifndef ONLINE_JUDGE 3 #define debug(x) cout << #x << ": " << x << endl 4 #else 5 #define debug(x) 6 #endif 7 using namespace std; 8 typedef long long ll; 9 const int MAXN=6e5+7; 10 const int INF=0x3f3f3f3f; 11 const int MOD=1e9+7; 12 13 int ans1[MAXN],ans2[MAXN],a[MAXN],pos[MAXN],sum[MAXN]; 14 int n,m; 15 16 int lowbit(int x) {return x&(-x);} 17 18 void add(int x,int val) 19 { 20 while(x<MAXN) 21 { 22 sum[x]+=val; 23 x+=lowbit(x); 24 } 25 } 26 27 int ask(int x) 28 { 29 int res=0; 30 while(x) 31 { 32 res+=sum[x]; 33 x-=lowbit(x); 34 } 35 return res; 36 } 37 38 int main() 39 { 40 ios::sync_with_stdio(false); 41 cin.tie(0); 42 cin>>n>>m; 43 for(int i=1;i<=n;++i) 44 { 45 ans1[i]=ans2[i]=i; 46 pos[i]=i+m; 47 } 48 for(int i=0;i<m;++i) 49 { 50 cin>>a[i]; 51 ans1[a[i]]=1; 52 } 53 for(int i=1;i<=n;++i) 54 add(pos[i],1); 55 for(int i=0;i<m;++i) 56 { 57 int p=a[i]; 58 ans2[p]=max(ans2[p],ask(pos[p])); 59 add(pos[p],-1); 60 pos[p]=m-i; 61 add(pos[p],1); 62 } 63 for(int i=1;i<=n;++i) 64 ans2[i]=max(ans2[i],ask(pos[i])); 65 for(int i=1;i<=n;++i) 66 cout<<ans1[i]<<‘ ‘<<ans2[i]<<‘\n‘; 67 return 0; 68 }
原文地址:https://www.cnblogs.com/Zzqf/p/12196001.html