zoukankan      html  css  js  c++  java
  • [Contest on 我又忘了] 咋回事啊

    ( ext{CF480E Parking Lot})

    解法

    ( ext{Method 1})(mathcal O(nmk))

    这个都没想到真的不应该...

    对于每次修改都暴力改,然后进行一个 (mathcal O(nm))(mathtt{dp}):令 (dp_{i,j}) 为以 ((i,j)) 为右下角的最大正方形。就有:

    [dp_{i,j}=min{dp_{i-1,j},dp_{i,j-1},dp_{i-1,j-1}}+1 ]

    具体画三个 (mathtt{dp}) 值对应的正方形就可以感性地证明。

    ( ext{Method 2})(mathcal O(n^2))

    当修改具有永久性,我们可以尝试将其离线,观察某种顺序遍历是否具有性质。

    比如这题如果倒序遍历修改,就有个非常神奇的性质 —— 如果更新了最大正方形,那么这个正方形一定包含被撤销的障碍!

    据此可以维护 (up_{i,j},down_{i,j}) 分别表示从 ((i,j)) 开始向上/下能延伸的最长长度。每次撤销障碍修改是 (mathcal O(n)) 的。

    如何求解此时的最大正方形?直接求解似乎不太好搞,我们可以看一下如何 ( m check) 长度为 (l) 的正方形。由于这个正方形包含了被撤销的障碍 ((x,y)),不妨以第 (x) 行为基准线,分别往上、往下延伸,再把它们拼在一起。

    比如对于往上延伸,从第一列往右扫,对于 (up_{x,j}) 维护一个单增的单调队列。因为只 ( m check) 长度为 (l) 的正方形,所以当队列长度大于 (l) 时可以踢掉队头,使长度更大。单次是 (mathcal O(m)) 的。

    但是这只是 ( m check) 啊?其实可以每次暴力扩展 (ans+1)。首先,可以保证 ( m check) 只能 成功 (min{n,m}) 次。其次,对于 (k) 次询问,每次只可能有一次 失败,所以总时间复杂度 (mathcal O(nk+m(n+k)))

    ( ext{Method 3})(mathcal O(n^2))

    如果想到了倒序修改,但是没有想到暴力扩展 (ans+1)?可以用尺取法来 (mathcal O(m)) 地计算最大正方形。

    具体而言,设置两个指针 (l,r),假设当前上下能扩展的最长长度为 (L),那么如果 (r-l+1ge L),此时再扩展 (r) 指针显然没有任何意义。于是将 (l) 指针加一。反之,则继续扩展。

    ( ext{Method 4})(mathcal O(n^2))

    这题有在线做法,但是我太弱没看懂,所以就咕咕咕了。

    代码

    在具体实现时,用的是开区间。

    #include <cstdio>
    #define print(x,y) write(x),putchar(y)
    
    template <class T> 
    inline T read(const T sample) {
    	T x=0; char s; bool f=0;
    	while((s=getchar())>'9' or s<'0')
    		f|=(s=='-');
    	while(s>='0' and s<='9')	
    		x=(x<<1)+(x<<3)+(s^48),
    		s=getchar();
    	return f?-x:x;
    }
    
    template <class T>
    inline void write(const T x) {
    	if(x<0) {
    		putchar('-');
    		write(-x);
    		return;
    	}
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    }
    
    #include <iostream>
    using namespace std;
    
    const int maxn=2005;
    
    char g[maxn][maxn];
    int n,m,k,Qx[maxn],Qy[maxn],A[maxn];
    int up[maxn][maxn],down[maxn][maxn];
    class Queue {
    public:
    	int l,r,q[maxn],v[maxn],tp;
    	
    	void Clear() {l=1,r=tp=0;}
    	
    	void Push(int k) {
    		v[++tp]=k;
    		while(l<=r and v[q[r]]>=k) --r;
    		q[++r]=tp; 
    	}
    	
    	void Pop(int x) {
    		while(l<=r and q[l]<=x) ++l;
    	}
    	
    	int Top() {
    		return l<=r?v[q[l]]:0;
    	}
    } Up,Down;
    
    void U_update(int j) {
    	for(int i=1;i<=n;++i)
    		if(g[i][j]^'X')
    			up[i][j]=up[i-1][j]+1;
    		else up[i][j]=0;
    }
    
    void D_update(int j) {
    	for(int i=n;i>=1;--i)
    		if(g[i][j]^'X')
    			down[i][j]=down[i+1][j]+1;
    		else down[i][j]=0;
    }
    
    int FuckIt(int i) {
    	if(!i) return 0;
    	int ans=0,L=0;
    	Up.Clear(),Down.Clear();
    	for(int l=1,r=1;l<=m;++l) {
    		Up.Pop(l-1),Down.Pop(l-1);
    		do {
    			if(r<=m) {
    				Up.Push(up[i][r]);
    				Down.Push(down[i][r]);
    				++r;
    			}
    			L=Up.Top()+Down.Top()-1;
    			ans=max(ans,min(L,r-l));
    		} while(r<=m and r-l<L);
    	}
    	return ans;
    }
    
    int main() {
    	n=read(9),m=read(9),k=read(9);
    	for(int i=1;i<=n;++i)
    		scanf("%s",g[i]+1);
    	for(int i=1;i<=k;++i)
    		Qx[i]=read(9),Qy[i]=read(9),
    		g[Qx[i]][Qy[i]]='X';
    	for(int i=1;i<=m;++i)
    		U_update(i),D_update(i);
    	for(int i=1;i<=n;++i)
    		A[k+1]=max(A[k+1],FuckIt(i));
    	for(int i=k;i>=1;--i) {
    		A[i]=max(A[i+1],FuckIt(Qx[i+1]));
    		g[Qx[i]][Qy[i]]='.';
    		U_update(Qy[i]);
    		D_update(Qy[i]);
    	}
    	for(int i=1;i<=k;++i)
    		print(A[i],'
    ');
    	return 0;
    }
    

    ( ext{CF575A Fibonotci})

    解法

    当时一场考试好像三个半小时,我调这道题调了整场考试… 最后发现思路都挂了。

    先令

    [a_i=egin{bmatrix}0 & s_{i-1}\1 & s_iend{bmatrix} ]

    那么就有

    [egin{bmatrix}f_k & f_{k+1} end{bmatrix}=egin{bmatrix}0 &1end{bmatrix} imes a_1 imes ... imes a_k ]

    用线段树维护 (a_1)(a_n) 矩阵的乘积,将每个修改拆成两个,这样对于在 ([kn+1,kn+n]) 中的修改在线段树上修改即可。如果在 ([ln+1,rn]) 之间都没有修改的话,直接快速幂就行了。

    (n,m) 同阶,总时间复杂度 (mathcal O(8nlog n))

    代码

    #include <cstdio>
    #define print(x,y) write(x),putchar(y)
    
    template <class T>
    inline T read(const T sample) {
    	T x=0; bool f=0; char s;
    	while((s=getchar())>'9' or s<'0')
    		f|=(s=='-');
    	while(s>='0' and s<='9')
    		x=(x<<1)+(x<<3)+(s^48),
    		s=getchar();
    	return f?-x:x;
    }
    
    template <class T>
    inline void write(const T x) {
    	if(x<0) {
    		putchar('-');
    		write(-x);
    		return;
    	}
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    }
    
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int maxn=5e4+5;
    
    int n,m,mod,val[maxn];
    ll K;
    struct Modi {
    	ll x; int y;
    	bool op;
    } q[maxn<<1];
    
    inline int inc(int x,int y) {
    	return x+y>=mod?x+y-mod:x+y;
    }
    
    struct mat {
    	int a[2][2];
    	mat() {memset(a,0,sizeof a);}
     	
    	mat operator * (const mat &t) const {
    		mat r;
    		for(int i=0;i<2;++i)
    		for(int j=0;j<2;++j)
    			if(a[i][j])
    				for(int k=0;k<2;++k)
    					r.a[i][k]=inc(
    						r.a[i][k],
    						1ll*a[i][j]*t.a[j][k]%mod);
    		return r;
    	}
    } t[maxn<<2],cur,e,what,a[maxn],b[maxn];
    
    mat qkpow(ll y) {
    	mat r;
    	for(int i=0;i<2;++i)
    		r.a[i][i]=1;
    	while(y) {
    		if(y&1) r=r*e;
    		e=e*e; y>>=1;
    	}
    	return r;
    }
    
    void build(int o,int l,int r) {
    	if(l==r) 
    		return t[o]=a[l],void();
    	int mid=l+r>>1;
    	build(o<<1,l,mid);
    	build(o<<1|1,mid+1,r);
    	t[o]=t[o<<1]*t[o<<1|1];
    }
    
    void modify(int o,int l,int r,int p) {
    	if(l==r) 
    		return t[o]=what,void();
    	int mid=l+r>>1;
    	if(p<=mid)
    		modify(o<<1,l,mid,p);
    	else modify(o<<1|1,mid+1,r,p);
    	t[o]=t[o<<1]*t[o<<1|1];
    }
    
    inline int ID(ll x) {
    	return x%n==0?n:x%n;
    }
    
    int main() {
    	K=read(9ll),mod=read(9);
    	n=read(9);
    	for(int i=0;i<n;++i)
    		val[i]=read(9)%mod;
    	for(int i=1;i<=n;++i) {
    		a[i].a[1][0]=1;
    		a[i].a[0][1]=val[i-1];
    		a[i].a[1][1]=val[i%n];
    		b[i]=a[i];
    	}
    	m=read(9);
    	for(int i=1;i<=m;++i)
    		q[i].x=read(9ll),
    		q[i+m].x=q[i].x+1,
    		q[i].op=1,
    		q[i+m].y=q[i].y=read(9)%mod;
    	m<<=1;
    	sort(q+1,q+m+1,[](Modi a,Modi b) {
    		return a.x<b.x;
    	});
    	build(1,1,n);
    	cur.a[0][1]=1;
    	ll pos=0; int j;
    	for(int i=1;i<=m;i=j+1) {
    		if(q[i].x>K) break;
    		if(pos+n<q[i].x) {
    			e=t[1];
    			cur=cur*qkpow((q[i].x-1-pos)/n);
    		}
    		pos=(q[i].x-1)/n*n+n;
    		j=i;
    		while(j+1<=m and (q[i].x-1)/n==(q[j+1].x-1)/n)
    			++j;
    		for(int k=i;k<=j;++k) {
    			b[ID(q[k].x)].a[q[k].op][1]=q[k].y;
    			what=b[ID(q[k].x)];
    			modify(1,1,n,ID(q[k].x));
    		}
    		if((q[i].x-1)/n==(K-1)/n) {
    			pos-=n;
    			break;
    		}
    		cur=cur*t[1];
    		for(int k=i;k<=j;++k)
    			what=b[ID(q[k].x)]=a[ID(q[k].x)],
    			modify(1,1,n,ID(q[k].x));
    	}
    	if(pos+n<K) { 
    		e=t[1];
    		cur=cur*qkpow((K-1-pos)/n);
    		pos=(K-1)/n*n;
    	}
    	for(ll i=pos+1;i<=K;++i)
    		cur=cur*b[ID(i)];
    	print(cur.a[0][0],'
    ');
    	return 0;
    }
    
  • 相关阅读:
    让一个 csproj 项目指定多个开发框架
    推荐近乎免费的调试神器——OzCode
    再也不用克隆多个仓库啦!git worktree 一个 git 仓库可以连接多个工作目录
    .NET Core 和 .NET Framework 中的 MEF2
    将 WPF、UWP 以及其他各种类型的旧样式的 csproj 文件迁移成新样式的 csproj 文件
    .NET 中的轻量级线程安全
    卡诺模型(KANO Model)
    C#/.NET 匿名函数会捕获变量,并延长对象的生命周期
    迫不及待地体验了一把 C#8.0 中的可空引用类型(Nullable Reference)
    异步任务中的重新进入(Reentrancy)
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/15350877.html
Copyright © 2011-2022 走看看