思想——高维拆分低维组合
Posted Lnn.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了思想——高维拆分低维组合相关的知识,希望对你有一定的参考价值。
前言:将高维数据拆分成低维的组合,以降低时间复杂度 OR 用已知的数据结构来简化题目。
文章目录
NWERC 2020 I. Island Tour
题目类型:模拟、低维遍历
题意:n(400)个点形成圆环,每个人在点或者i到i+1的路上都有不同停留时间。三个人要同时遍历这个环,问是否存在三个起点,使得三人在遍历的过程不会相遇。
解析: 最暴力的方法:枚举所有的三个起点(n^3),模拟一遍(n),总时间复杂度O(n ^ 4)。
优化:按照上面的模拟思路,枚举所有的两个起点,模拟一遍,就可以处理出两个人之间的关系O(n^3),存起来g[a][b][i][j]就是a在i起点,b在j起点能否成功。那么按照这个方式处理三个人之间两两的关系。最后在枚举三个起点,O(1)来判断。总时间复杂度O(4 * n^3)
code:
#include <bits\\stdc++.h>
#define ll long long
#define endl '\\n'
#define maxn 444
using namespace std;
ll n,to[maxn],a[maxn][3];
bool c[3][3][maxn][maxn];
void scan()
cin >> n ;
for(ll i = 1 ; i <= n ; ++i)cin >> to[i] ;
for(ll i = 1 ; i <= n ; ++i)cin >> a[i][0] ;
for(ll i = 1 ; i <= n ; ++i)cin >> a[i][1] ;
for(ll i = 1 ; i <= n ; ++i)cin >> a[i][2] ;
bool run(ll x,ll y,ll fx,ll fy)
ll hx = 0 , hy = 0;
ll xt = 0 , yt = 0;
while(hx < n-1 && hy < n-1)
ll nedx = a[fx][x] + to[fx] - xt;
ll nedy = a[fy][y] + to[fy] - yt;
if(nedx < nedy)
fx++;
hx++;
xt = 0;
yt += nedx;
else if(nedx > nedy)
fy++;
hy++;
yt = 0;
xt += nedy;
else
xt = yt = 0;
fx++ , fy++;
hx++ , hy++;
if(fx > n)fx = 1;
if(fy > n)fy = 1;
if(fx == fy)
if(xt < a[fx][x] && yt < a[fy][y])return 0;
return 1;
void match(ll x,ll y)
for(ll i = 1 ; i <= n ; ++i)
for(ll j = 1 ; j <= n ; ++j)
if(i == j)continue;
c[x][y][i][j] = run(x,y,i,j);
void solve()
match(0,1);
match(0,2);
match(2,1);
for(ll i = 1 ; i <= n ; ++i)
for(ll j = 1 ; j <= n ; ++j)
if(i == j)continue;
for(ll k = 1 ; k <= n ; ++k)
if(k == i || k == j)continue;
if(c[0][1][i][j] && c[0][2][i][k] && c[2][1][k][j])
cout << i << " " << j << " " << k << endl ;
return;
cout << "impossible" << endl ;
int main()
ios::sync_with_stdio(false);
///cin.tie(0);cout.tie(0);
ll t = 1;
while(t--)
scan();
solve();
Codeforces Round #574 (Div. 2) E. OpenStreetMap
题目传送门
题目类型:区间最小值、矩形拆线段
题意:给出一个n * m的矩阵,求出所有a * b的子矩阵中的最小值的和。
解析:很明显,博主并不会低于n^2复杂度的矩形最小值。只能把问题变简单点。先处理行最小值,在这个基础上处理列最小值就OK啦。
具体的:先把原矩阵处理成行最小值,比如a[i][j]代表的是a[i][j] 到 a[i][j+b-1]的最小值。就变成了一个n * (m-b+1)的行最小值矩阵。在对这个矩阵列求最小值,a[i][j]就代表左上角a[i][j] 右下角a[i+a-1][j+b-1]的矩形的最小值啦。最后对这个矩形求和即可。
区间最小值,可以用st表、线段树等,但是这题区间长度是固定的,可以用单调队列。
code:
#include <bits\\stdc++.h>
#define ll int
#define maxn 3030
using namespace std;
void eninit();
ll n,m,a,b,ql,qr,q[maxn],h[maxn][maxn],dt[maxn][maxn];
long long g[maxn*maxn];
void scan()
long long g0,x,y,z;
cin >> n >> m >> a >> b ;
cin >> g[0] >> x >> y >> z ;
for(ll i = 1 ; i <= n*m ; ++i)g[i] = (g[i-1]*x+y) % z;
for(ll i = 1 ; i <= n ; ++i)
for(ll j = 1 ; j <= m ; ++j)
h[i][j] = g[(i-1)*m + j-1];
void Deque(ll h[] , ll res[] ,ll m,ll b) ///单调队列维护最小值
for(ll i = 0 ; i <= 3003 ; ++i)q[i] = 0;
ql = 1 , qr = 0;
for(ll j = 1 ; j <= m ; ++j)
while(ql <= qr && h[ q[qr] ] > h[j])--qr; ///最大值改这里的>
q[++qr] = j;
if(j >= b)
while(j - q[ql] + 1 > b)++ql;
res[j - b + 1] = h[ q[ql] ];
void rev(ll h[][maxn] , ll n,ll m)
ll maxx = max(n,m);
for(ll i = 1 ; i <= maxx ; ++i)
for(ll j = i+1 ; j <= maxx ; ++j)
swap(h[i][j] , h[j][i]);
void solve()
for(ll i = 1 ; i <= n ; ++i)
Deque(h[i] , dt[i] ,m,b);
rev(dt , n,m-b+1);
for(ll i = 1 ; i <= m-b+1 ; ++i)
Deque(dt[i] , h[i] ,n,a);
rev(h , m-b+1,n-a+1);
long long ans = 0;
for(ll i = 1 ; i <= n-a+1 ; ++i)
for(ll j = 1 ; j <= m-b+1 ; ++j)
ans += h[i][j];
cout << ans << endl ;
int main()
ios::sync_with_stdio(false); cin.tie(0);cout.tie(0);
scan();
solve();
总结
写完博客继续写题了…看到类似的再来更新…
以上是关于思想——高维拆分低维组合的主要内容,如果未能解决你的问题,请参考以下文章