20210810 玩游戏,排列,最短路,矩形

考场

在 hz 头一次打 4 道题的比赛,有点刺激

开题,发现啥也不会
感觉 T1 T3 比较可做
先写 T4,尝试通过值域来优化连边(毕竟有一个 \(n=20000\) 的点),假了之后改成 \(O(n^2)\) 暴力。
T2 直接全排列,打了各种表只发现 \(k=1\) 的答案为 \(2^{n-1}\),感觉后面是阴间的 DP 或数学,50pts 很香就没多想。
T1 先想到一个 zz 的 \(O(n^2)\) 做法:每次让左端点 \(-1\),右端点如果能移到右边一个前缀和更小的位置就移,否则等左端点移到 \(1\) 再移,并且可以优化到 \(O(n\log n)\)(二分+ST 表,写完和 \(O(2^n)\) 拍上了,意识到 \(O(2^n)\) 的做法加上记忆化就 \(O(n^2)\) 了,然后发现第一个做法挂了,并在 2min 构造出了小数据。。。心态小炸。发现第二个做法也可以用类似的优化,就先写了暴力 RMQ 拍上了,极限数据要跑 3,4s。改成二分+ST 表后零点几秒就跑完了,只能寄希望与数据水。
最后 1.5h 看 T3,一个 sb 做法是状压+最短路,那岂不是加个 bitset 就能混很多分?发现它是捆绑测试,并且当时只想到了 dij,认为把 bitset 丢进堆里时间复杂度会爆,于是没有写。。。最后在尝试 tarjan 和 floyed 中结束比赛

res

rk2 100+50+20+20
T1 数据极水,各种不保证正确性/复杂度的做法都过了

rk1 付文暄 100+50+20+50
rk3 张锦霄 10+30+100+30

Sol

又没时间写了

T1 sol 说这题是 hdu6326 的弱化版

考场代码(不保证复杂度):

const int N = 1e5+5;
int T,n,l,r;
LL a[N];

unordered_map<int,int> vis[N];

namespace st {
int lg[N],f[17][N],g[17][N];
int _max(int x,int y) { return a[x]>a[y] ? x : y; }
int _min(int x,int y) { return a[x]<a[y] ? x : y; }
void main() {
	For(i,1,n) f[0][i] = g[0][i] = i;
	For(j,1,16) for(int i = 1; i+(1<<j)-1 <= n; ++i)
		f[j][i] = _max(f[j-1][i],f[j-1][i+(1<<j-1)]),
		g[j][i] = _min(g[j-1][i],g[j-1][i+(1<<j-1)]);
}
int qmax(int l,int r) {
	int k = lg[r-l+1];
	return _max(f[k][l],f[k][r-(1<<k)+1]);
}
int qmin(int l,int r) {
	int k = lg[r-l+1];
	return _min(g[k][l],g[k][r-(1<<k)+1]);
}
}

void update(int &l,int &r) {
	int ll = 1, rr = l;
	while( ll < rr ) {
		int mid = ll+rr>>1;
		if( a[st::qmin(mid,l)] >= a[r] ) rr = mid;
		else ll = mid+1;
	}
	l = st::qmax(ll,l);
	ll = r, rr = n;
	while( ll < rr ) {
		int mid = ll+rr+1>>1;
		if( a[st::qmax(r,mid)] <= a[l] ) ll = mid;
		else rr = mid-1;
	}
	r = st::qmin(r,ll);
}
bool dfs(int l,int r) {
	if( l == 1 && r == n ) return 1;
	update(l,r);
	if( vis[l][r] ) return 0;
	vis[l][r] = 1;
	if( l == 1 && r == n ) return 1;
	if( a[r]-a[l-1] <= 0 && l > 1 && dfs(l-1,r) ) return 1;
	if( a[r+1]-a[l] <= 0 && r < n && dfs(l,r+1) ) return 1;
	return 0;
}
void solve() {
	read(n,l); r = l;
	For(i,1,n) read(a[i]), a[i] += a[i-1];
	st::main();
	int ll,rr;
	do {
		ll = l, rr = r;
		update(l,r);
	} while( l != ll || r != rr );
	puts(dfs(l,r) ? "Yes" : "No");
}

signed main() {
	// freopen("a.in","r",stdin);
	// freopen("a.out","w",stdout);
	For(i,2,1e5) st::lg[i] = st::lg[i>>1]+1;
	read(T);
	while( T-- ) {
		For(i,1,n) vis[i].clear();
		solve();
	}
	return 0;
}
T2

发现最大值两边的区间是一个同样的子问题,考虑 DP
\(f[i,j,0/1,0/1]\) 为长度为 \(i\) 的区间,左右是否靠着边界,在 \(\le j\) 次操作删完的排列数,转移时枚举最大值位置。

const int N = 1e3+5;
int n,m,mod;

int C[N][N];
LL f[N][12][2][2];

signed main() {
	read(n,m,mod);
	if( m > ceil(log2(n)) ) { puts("00"); return 0; }
	For(i,0,n) {
		C[i][0] = 1;
		For(j,1,i) C[i][j] = (C[i-1][j-1] + C[i-1][j]) %mod;
	}
	For(i,0,m) f[0][i][0][0] = f[0][i][0][1] = f[0][i][1][0] = f[0][i][1][1] = 1;
	For(i,1,n) For(j,1,m) {
		For(k,1,i) {
			f[i][j][0][0] += f[k-1][j][0][1] * f[i-k][j][1][0] %mod * C[i-1][k-1] %mod;
			f[i][j][0][1] += f[k-1][j][0][1] * f[i-k][j-1][1][1] %mod * C[i-1][k-1] %mod;
			f[i][j][1][0] += f[k-1][j-1][1][1] * f[i-k][j][1][0] %mod * C[i-1][k-1] %mod;
			f[i][j][1][1] += (f[k-1][j][1][1]*f[i-k][j][1][1]%mod - (f[k-1][j][1][1]-f[k-1][j-1][1][1])*(f[i-k][j][1][1]-f[i-k][j-1][1][1])%mod) * C[i-1][k-1] %mod;
		}
		f[i][j][0][0] %= mod, f[i][j][0][1] %= mod, f[i][j][1][0] %= mod, f[i][j][1][1] %= mod;
	}
	LL ans = f[n][m][0][0]-f[n][m-1][0][0];
	write((ans+mod)%mod);
	return iocl();
}
T3

sol 做法

二维 spfa 做法,不保证正确性和复杂度

const int N = 255, inf = 0x3f3f3f3f;
int n,m,val[N];
vector<int> to[N],rto[N];

int dis[N][N];
bool inq[N][N];
bitset<251> vis[N][N];
queue<PII> que;

int spfa() {
	memset(dis,0x3f,sizeof dis);
	dis[1][1] = val[1], vis[1][1][1] = 1, que.push(MP(1,1));
	while( !que.empty() ) {
		int u1 = que.front().fi, u2 = que.front().se; que.pop();
		inq[u1][u2] = 0;
		for(int v : to[u1]) {
			int w = vis[u1][u2][v] ? 0 : val[v];
			if( dis[u1][u2]+w < dis[v][u2] ) {
				dis[v][u2] = dis[u1][u2]+w,
				vis[v][u2] = vis[u1][u2], vis[v][u2][v] = 1;
				if( !inq[v][u2] ) inq[v][u2] = 1, que.push(MP(v,u2));
			}
		}
		for(int v : rto[u2]) {
			int w = vis[u1][u2][v] ? 0 : val[v];
			if( dis[u1][u2]+w < dis[u1][v] ) {
				dis[u1][v] = dis[u1][u2]+w,
				vis[u1][v] = vis[u1][u2], vis[u1][v][v] = 1;
				if( !inq[u1][v] ) inq[u1][v] = 1, que.push(MP(u1,v));
			}
		}
	}
	return dis[n][n]!=inf ? dis[n][n] : -1;
}

signed main() {
	read(n,m);
	For(i,1,n) read(val[i]);
	For(i,1,m) {
		int x,y; read(x,y);
		to[x].pb(y), rto[y].pb(x);
	}
	write(spfa());
	return iocl();
}
T4

扫描线做法

const int N = 1e5+5;
int n,r1[N],c1[N],r2[N],c2[N];

int ans,fa[N];
vector<int> add[N],del[N];

int find(int x) { return fa[x]==x ? x : fa[x]=find(fa[x]); }
void merge(int x,int y) { fa[find(x)] = find(y); }

#define ls (u<<1)
#define rs (u<<1|1)
struct Node { int l,r,col,sum,add; } t[N*4];
void up(int u) {
	if( t[ls].col && t[rs].col && t[ls].col == t[rs].col ) t[u].col = t[ls].col;
	else t[u].col = 0;
	t[u].sum = max(t[ls].sum,t[rs].sum);
}
void down(int u,int x,int y) {
	t[u].sum += x, t[u].add += x;
	if( !t[u].sum ) t[u].col = 0;
	else if( y ) t[u].col = y;
}
void down(int u)
	{ down(ls,t[u].add,t[u].col), down(rs,t[u].add,t[u].col), t[u].add = 0; }
void build(int u,int l,int r) {
	t[u].l = l, t[u].r = r;
	if( l == r ) return;
	int mid = l+r>>1;
	build(ls,l,mid), build(rs,mid+1,r);
}
void modify(int u,int l,int r,int x,int y) {
	if( l <= t[u].l && t[u].r <= r ) { down(u,x,y); return; }
	down(u);
	if( l <= t[ls].r ) modify(ls,l,r,x,y);
	if( t[rs].l <= r ) modify(rs,l,r,x,y);
	up(u);
}
void query(int u,int l,int r,int x) {
	if( !t[u].sum ) return;
	if( l <= t[u].l && t[u].r <= r && t[u].col) { merge(x,t[u].col); return; }
	down(u);
	if( l <= t[ls].r ) query(ls,l,r,x);
	if( t[rs].l <= r ) query(rs,l,r,x);
	up(u);
}
#undef ls
#undef rs

signed main() {
	// freopen("a.in","r",stdin);
	// freopen("a.out","w",stdout);
	read(n);
	For(i,1,n) {
		read(r1[i],c1[i],r2[i],c2[i]);
		add[r1[i]].pb(i), del[r2[i]].pb(i);
		fa[i] = i;
	}
	build(1,1,1e5);
	For(i,1,1e5) {
		for(int j : add[i]) query(1,c1[j],c2[j],j), modify(1,c1[j],c2[j],1,j);
		for(int j : del[i]) modify(1,c1[j],c2[j],-1,0);
	}
	For(i,1,n) if( find(i) == i ) ++ans;
	write(ans);
	return iocl();
}
/*
3
1 3 6 4
2 1 3 4
4 2 5 2
*/

sol 做法 by szs



#include<bits/stdc++.h>
using namespace std;
#define uu unsigned
#define forg(i,x) for(int i=fir[x];i;i=nxt[i])
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define scanf abc=scanf
int abc;
typedef long long ll;
typedef uu long long ull;
typedef pair<int,int>pii;
typedef vector<int>VI;
inline int rd(int l,int r){return rand()%(r-l+1)+l;}

const int mxn=1e5+3,S=1e5;
struct jg{int x1,x2,y1,y2;bool hh;}b[mxn];
int n;bool vs[mxn];
bool cmp1(const jg&a,const jg&b){return a.x1<b.x1;}
bool cmp2(const jg&a,const jg&b){return a.x2>b.x2;}
struct zzz{
    int a[mxn];
    int tk[mxn],tn;
    void add(int x,int y){tk[++tn]=x;for(;x<=S;x+=x&-x)a[x]=max(a[x],y);}
    int ask(int x){int r=0;for(;x;x&=x-1)r=max(r,a[x]);return r;}
    void clr(){while(tn){int x=tk[tn--];for(;x<=S;x+=x&-x)a[x]=0;}}
}ar;
void cdq(int l,int r){
    if(l==r)return;
    int md=(l+r)>>1;cdq(l,md),cdq(md+1,r);
    sort(b+l,b+md+1,cmp2),sort(b+md+1,b+r+1,cmp2);
    for(int i=md+1,p1=l-1;i<=r;++i){
        while(p1!=md+1&&b[p1+1].x2>b[i].x2)++p1,ar.add(b[p1].y1,b[p1].y2);
        b[i].hh|=ar.ask(b[i].y1)>=b[i].y2;
    }
    ar.clr();
}
#define mid ((l+r)>>1)
struct seee{
    set<pii>a[mxn*4];
    void ins(int lc,int rc,pii v,int x=1,int l=1,int r=S){
        if(lc<=l&&r<=rc)return a[x].insert(v),void();
        if(lc<=mid)ins(lc,rc,v,x*2,l,mid);if(rc>mid)ins(lc,rc,v,x*2+1,mid+1,r);
    }
    void del(int lc,int rc,pii v,int x=1,int l=1,int r=S){
        if(lc<=l&&r<=rc)return a[x].erase(v),void();
        if(lc<=mid)del(lc,rc,v,x*2,l,mid);if(rc>mid)del(lc,rc,v,x*2+1,mid+1,r);
    }
    pii ask(int k,int lc,int rc,int x=1,int l=1,int r=S){
        auto it=a[x].lower_bound(pii(lc,0));if(it!=a[x].end()&&it->first<=rc)return *it;
        if(l==r)return pii(-1,-1);
        return k<=mid?ask(k,lc,rc,x*2,l,mid):ask(k,lc,rc,x*2+1,mid+1,r);
    }
}sh,sl;
#undef mid
void ins(int k){
    sh.ins(b[k].x1,b[k].x2,pii(b[k].y1,k)),sh.ins(b[k].x1,b[k].x2,pii(b[k].y2,k));
    sl.ins(b[k].y1,b[k].y2,pii(b[k].x1,k)),sl.ins(b[k].y1,b[k].y2,pii(b[k].x2,k));
}
void del(int k){
    sh.del(b[k].x1,b[k].x2,pii(b[k].y1,k)),sh.del(b[k].x1,b[k].x2,pii(b[k].y2,k));
    sl.del(b[k].y1,b[k].y2,pii(b[k].x1,k)),sl.del(b[k].y1,b[k].y2,pii(b[k].x2,k));
}
void dfs(int x){
    assert(!vs[x]),vs[x]=1;del(x);
    pii k;
    while(k=sl.ask(b[x].y1,b[x].x1,b[x].x2),k.first!=-1)dfs(k.second);
    while(k=sl.ask(b[x].y2,b[x].x1,b[x].x2),k.first!=-1)dfs(k.second);
    while(k=sh.ask(b[x].x1,b[x].y1,b[x].y2),k.first!=-1)dfs(k.second);
    while(k=sh.ask(b[x].x2,b[x].y1,b[x].y2),k.first!=-1)dfs(k.second);
}
int main(){
    scanf("%d",&n);for(int i=1;i<=n;++i){int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);b[i]={x1,x2,y1,y2,0};}
    sort(b+1,b+n+1,cmp1);cdq(1,n);
    for(int i=1;i<=n;++i)if(!b[i].hh)ins(i);else vs[i]=1;
    int re=0;
    for(int i=1;i<=n;++i)if(!vs[i])++re,dfs(i);
    printf("%d\n",re);
    return 0;
}

posted @ 2021-08-11 06:39  401rk8  阅读(96)  评论(2编辑  收藏  举报