• 计蒜客 NOIP 提高组模拟竞赛第一试 补记


    计蒜客 NOIP 提高组模拟竞赛第一试 补记

    A. 广场车神

    题目大意:

    一个(n imes m(n,mle2000))的网格,初始时位于左下角的((1,1))处,终点在右上角的((n,m))。每次移动可以选择移动到自己右上方的某一方格,且横坐标和纵坐标的变化都不能超过(k(kle2000))。求一共有多少种移动方案?

    思路:

    (f[i][j])表示走到((i,j))的方案数,一边DP一边维护二维前缀和即可。

    时间复杂度(mathcal O(nm))

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int N=2001,mod=998244353;
    int f[N][N],g[N][N];
    inline int sum(int x1,const int &x2,int y1,const int &y2) {
    	x1=std::max(x1-1,0);
    	y1=std::max(y1-1,0);
    	return (((g[x2][y2]+g[x1][y1])%mod-(g[x1][y2]+g[x2][y1])%mod)%mod+mod)%mod;
    }
    int main() {
    	freopen("racing.in","r",stdin);
    	freopen("racing.out","w",stdout);
    	const int n=getint(),m=getint(),k=getint();
    	f[1][1]=g[1][1]=1;
    	for(register int i=1;i<=n;i++) {
    		for(register int j=1;j<=m;j++) {
    			if(i==1&&j==1) continue;
    			g[i][j]=((g[i-1][j]+g[i][j-1]-g[i-1][j-1])%mod+mod)%mod;
    			f[i][j]=sum(i-k,i,j-k,j);
    			(g[i][j]+=f[i][j])%=mod;
    		}
    	}
    	printf("%d
    ",f[n][m]);
    	return 0;
    }
    

    B. 敌对势力

    题目大意:

    给定一棵(n(nle10^5))个结点的树,(m(mle10^5))次询问,每次询问路径((a,b))和路径((c,d))是否有交。

    思路:

    树链剖分后,有线段树在((a,b))路径上+1,然后看一下((c,d))路径上是否为(0)即可。

    时间复杂度(mathcal O(mlog^2n))

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<vector>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int N=1e5+1;
    std::vector<int> e[N];
    inline void add_edge(const int &u,const int &v) {
    	e[u].push_back(v);
    	e[v].push_back(u);
    }
    int dep[N],par[N],size[N],son[N],top[N],dfn[N];
    void dfs(const int &x,const int &par) {
    	size[x]=1;
    	::par[x]=par;
    	dep[x]=dep[par]+1;
    	for(auto &y:e[x]) {
    		if(y==par) continue;
    		dfs(y,x);
    		size[x]+=size[y];
    		if(size[y]>size[son[x]]) son[x]=y;
    	}
    }
    class SegmentTree {
    	#define _left <<1
    	#define _right <<1|1
    	#define mid ((b+e)>>1)
    	private:
    		bool val[N<<2],tag[N<<2];
    	public:
    		void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const int &t) {
    			val[p]+=t;
    			if(b==l&&e==r) {
    				tag[p]+=t;
    				return;
    			}
    			if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r),t);
    			if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r,t);
    		}
    		bool query(const int &p,const int &b,const int &e,const int &l,const int &r) const {
    			if(tag[p]) return true;
    			if(b==l&&e==r) return val[p];
    			if(l<=mid&&query(p _left,b,mid,l,std::min(mid,r))) return true;
    			if(r>mid&&query(p _right,mid+1,e,std::max(mid+1,l),r)) return true;
    			return false;
    		}
    	#undef _left
    	#undef _right
    	#undef mid
    };
    SegmentTree sgt;
    void dfs(const int &x) {
    	dfn[x]=++dfn[0];
    	top[x]=x==son[par[x]]?top[par[x]]:x;
    	if(son[x]) dfs(son[x]);
    	for(auto &y:e[x]) {
    		if(y==par[x]||y==son[x]) continue;
    		dfs(y);
    	}
    }
    inline void modify(int x,int y,const int &t) {
    	while(top[x]!=top[y]) {
    		if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
    		sgt.modify(1,1,dfn[0],dfn[top[x]],dfn[x],t);
    		x=par[top[x]];
    	}
    	if(dep[x]<dep[y]) std::swap(x,y);
    	sgt.modify(1,1,dfn[0],dfn[y],dfn[x],t);
    }
    inline bool query(int x,int y) {
    	bool ret=false;
    	while(top[x]!=top[y]) {
    		if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
    		ret|=sgt.query(1,1,dfn[0],dfn[top[x]],dfn[x]);
    		x=par[top[x]];
    	}
    	if(dep[x]<dep[y]) std::swap(x,y);
    	ret|=sgt.query(1,1,dfn[0],dfn[y],dfn[x]);
    	return ret;
    }
    int main() {
    	freopen("enemy.in","r",stdin);
    	freopen("enemy.out","w",stdout);
    	const int n=getint(),m=getint();
    	for(register int i=1;i<n;i++) {
    		add_edge(getint(),getint());
    	}
    	dfs(1,0);
    	dfs(1);
    	for(register int i=0;i<m;i++) {
    		const int a=getint(),b=getint(),c=getint(),d=getint();
    		modify(a,b,1);
    		puts(query(c,d)?"NO":"YES");
    		modify(a,b,-1);
    	}
    	return 0;
    }
    

    C. 提高水平

    题目大意:

    (n(nle20))个东西,第(i)个东西放在第(j)个东西前可以获得(a_{i,j})的收益。问如何排列这些东西使得收益最大?

    思路:

    状压DP。

    时间复杂度(mathcal O(2^nn))

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int N=20;
    int a[N][N],f[1<<N],w[N][1<<N];
    inline int lowbit(const int &x) {
    	return x&-x;
    }
    inline int lg2(const float &x) {
    	return ((unsigned&)x>>23&255)-127;
    }
    int main() {
    	freopen("proficiency.in","r",stdin);
    	freopen("proficiency.out","w",stdout);
    	const int n=getint(),all=(1<<n)-1;
    	for(register int i=0;i<n;i++) {
    		for(register int j=0;j<n;j++) {
    			a[i][j]=getint();
    		}
    	}
    	for(register int i=0;i<n;i++) {
    		for(register int j=1;j<=all;j++) {
    			w[i][j]=w[i][j^lowbit(j)]+a[lg2(lowbit(j))][i];
    		}
    	}
    	for(register int i=1;i<=all;i++) {
    		for(register int j=0;j<n;j++) {
    			if((i>>j)&1) {
    				f[i]=std::max(f[i],f[i^(1<<j)]+w[j][i]);
    			}
    		}
    	}
    	printf("%d
    ",f[all]);
    	return 0;
    }
    
  • 相关阅读:
    Java程序员之JS(一) 入门
    Java虚拟机(一)之开篇
    JDK/JRE/JVM区别与联系
    web开发视频(一)之环境准备
    Spring MVC 教程,快速入门,深入分析
    Java中“==和equals”的区别
    如何查看电脑最大支持多少GB内存
    win10 计算器calc命令打不开
    Win10图标显示不正常解决办法
    在系统右键菜单上添加程序
  • 原文地址:https://www.cnblogs.com/skylee03/p/9687939.html
Copyright © 2020-2023  润新知