给定一个有 n n 个元素的序列,元素编号为 1…n 1 … n ,每个元素有 k k 个属性 p1,p2,p3,…,pk p 1 , p 2 , p 3 , … , p k ,求序列中满足 i<j i < j 且 1≤t≤k,pti<ptj 1 ≤ t ≤ k , p i t < p j t 的数对 (i,j) ( i , j ) 的个数。
可以用bitset
解决多维偏序问题。
用st[i][j]
表示比第 i i 个元素的第 j j 维小的位置的状态(bitset),最后计算的时候取交集即可。
然后我就兴奋地交了一发,看见一排的 MMMMMMMMMM M M M M M M M M M M ,发现bitset
会炸空间啊,,,
然后去网上翻了一下,发现可以用分块写耶,时间复杂度 O(knn−−√) O ( k n n ) ,我果然太菜了,这都想不到。
感觉时间可以把KDTree吊起来打?
/**************************************
* Au: Hany01
* Prob: [COGS2639][HZOI2015] 偏序++
* Date: Mar 18th, 2018
* Email: [email protected]
**************************************/
#include
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef vector<int> VI;
#define Rep(i , j) for (register int i = 0 , i##_end_ = j; i < i##_end_ ; ++ i)
#define For(i , j , k) for (register int i = (j) , i##_end_ = (k) ; i <= i##_end_ ; ++ i)
#define Fordown(i , j , k) for (register int i = (j) , i##_end_ = (k) ; i >= i##_end_ ; -- i)
#define Set(a , b) memset(a , b , sizeof(a))
#define SZ(a) ((int)(a.size()))
#define ALL(a) a.begin(), a.end()
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define Mod (1000000007)
#define y1 wozenmezhemecaia
#ifdef hany01
#define debug(...) fprintf(stderr , __VA_ARGS__)
#else
#define debug(...)
#endif
inline void File() {
freopen("partial_order_plus.in" , "r" , stdin);
freopen("partial_order_plus.out" , "w" , stdout);
}
template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
inline int read() {
register char c_; register int _ , __;
for (_ = 0 , __ = 1 , c_ = getchar() ; !isdigit(c_) ; c_ = getchar()) if (c_ == '-') __ = -1;
for ( ; isdigit(c_) ; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
return _ * __;
}
const int maxn = 40005, maxk = 8, Block = 205;
int n, k, rk[maxn][maxk], sa[maxn][maxk], block, num, bel[maxn];
bitset st[Block][maxk], tmp;
LL Ans;
inline bitset query(int rk, int j)
{
static bitset t;
int pos = bel[rk] - 1;
t = st[pos][j];
pos = block * pos + 1;
For(i, pos, rk) t.set(sa[i - 1][j]);
return t;
}
int main()
{
File();
//Init
n = read(), k = read();
For(j, 1, k) For(i, 1, n) rk[i][j] = read(), sa[rk[i][j]][j] = i;
++ k;
For(i, 1, n) rk[i][k] = i, sa[i][k] = i;
block = sqrt(n), num = (n - 1) / block + 1;
For(i, 1, n) bel[i] = (i - 1) / block + 1;
//Work out the answer of every blocks
For(j, 1, k)
For(i, 1, num) {
st[i][j] = st[i - 1][j];
For(k, max((i - 1) * block + 1, 2), min(i * block, n)) st[i][j].set(sa[k - 1][j]);
}
//Calc
For(i, 1, n) {
tmp = query(rk[i][1], 1);
For(j, 2, k) tmp &= query(rk[i][j], j);
Ans += tmp.count();
}
printf("%lld\n", Ans);
return 0;
}
//日出而作,日入而息。
//凿井而饮,耕田而食。
//帝力于我何有哉!
// --《击壤歌》