[暑假集训Day4T2]卡拉赞之夜

抹茶学长给的标程可以被卡到O(N2M2)???

考虑二分答案+暴力check+离散化+卡常数

首先进行离散化,其实判重的话会更快,但是由于矩阵元素大小太大了,hash判重MLE,所以我就直接记录了NM个元素之后排序,即可二分离散化后数组中的下标。

二分离散化数组的下标,对于每一个下标考虑暴力check。设数组pd,当pd[i][j]=1时,表示F(i,j)>=mid,对于需验证的答案mid,首先令mid--,这样只需判断比mid大的数即可(常数优化)。之后用O(NM)的时间计算pd数组(可以用bitset进行常常数优化,蒟蒻这里不太会,直接开的bool数组)这里有一个很重要的优化,如果一行中1的数量小于2,它一定不能作为矩阵的上界和下界,O(N)记录即可。最后枚举矩阵上下界,设上界为i行,下界为j行,枚举k列。当pd[i][k]==pd[j][k]==1时,可以作为矩阵的两个角,如果两列中列有两组以上这样的情况,那么答案mid是可行的,传回成功信息,如果对于所有行都不行的话,那么传回失败信息。最后,能用快读快写的地方尽量用快读快写,能用位运算的地方尽量用位运算。

加入以上优化后我成功地把O(N2M(logNM))的算法(N,M≤1000)卡到了568ms(逃)

参考代码如下:

 1 #include<iostream>
 2 #include<bitset>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<cstdlib> 
 6 using namespace std;
 7 inline int read() 
 8 {
 9     int x=0;
10     bool f=1;
11     char c=getchar();
12     for(; !isdigit(c); c=getchar()) if(c=='-') f=0;
13     for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+c-'0';
14     if(f) return x;
15     return 0-x;
16 }
17 int n,m,f[1010][1010],maxn=-1073741822,minn=1073741822,v[1000001];
18 inline bool check(int x)
19 {
20     x--;
21     bool p[1010]={},pd[1010][1010]={};
22     int ct[1010]={};
23     for(int i=1;i<=n;i++)
24         for(int j=1;j<=m;j++)
25             if(f[i][j]>x)pd[i][j]=1,ct[i]++;
26     for(int i=1;i<=n;i++)
27     {
28         if(ct[i]<2)p[i]=1;
29     }
30     for(int i=1;i<n;i++)
31     {
32         if(p[i])continue;
33         for(int j=i+1;j<=n;j++)
34         {
35             if(p[j])continue;
36             int cnt=0;
37             for(int k=1;k<=m;k++)
38                 if(pd[i][k]&pd[j][k])
39                 {
40                     cnt++;
41                     if(cnt>1) return 1;
42                 }
43         }
44     }
45     return false;
46 }
47 int main()
48 {
49     //srand(20050923);
50     int t=0;
51     n=read();m=read();
52     for(int i=1;i<=n;i++)
53         for(int j=1;j<=m;j++)
54         {
55             f[i][j]=read();
56             v[++t]=f[i][j];
57             maxn=max(maxn,f[i][j]);
58             minn=min(minn,f[i][j]);
59         }
60     sort(v+1,v+t+1);
61     int l=1,r=t,mid,tot=0;
62     while(l<=r)
63     {
64         mid=(l+r)>>1;
65         if(check(v[mid])) l=mid+1;
66         else r=mid-1;
67     }
68     cout<<v[l-1];
69     return 0;
70 }
View Code
原文地址:https://www.cnblogs.com/szmssf/p/11180858.html