• NOI.AC NOIP模拟赛 第六场 游记


    NOI.AC NOIP模拟赛 第六场 游记

    queen

    题目大意:

    在一个(n imes n(nle10^5))的棋盘上,放有(m(mle10^5))个皇后,其中每一个皇后都可以向上、下、左、右、左上、左下、右上、右下这(8)个方向移动。其中每一个皇后可以攻击这八个方向上离它最近的皇后。

    求有多少皇后被攻击到(0,1,ldots,8)次。 保证(m)个皇后中任意两个不在同一个位置。

    思路:

    考虑左右方向的攻击,对每一行开一个set,按列编号插入,看一下是否存在前驱/后继即可。其余方向同理。

    时间复杂度(mathcal O(mlog m))

    源代码:

    #include<set>
    #include<cstdio>
    #include<cctype>
    #include<climits>
    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;
    int n,m,cnt[N],t[N],x[N],y[N];
    std::set<int> s[N*2];
    inline void reset() {
    	for(register int i=1;i<=n*2;i++) {
    		s[i].clear();
    		s[i].insert(INT_MIN);
    		s[i].insert(INT_MAX);
    	}
    }
    inline int query(const int &x,const int &y) {
    	int ret=0;
    	if(*--s[x].lower_bound(y)!=INT_MIN) ret++;
    	if(*s[x].upper_bound(y)!=INT_MAX) ret++;
    	return ret;
    }
    int main() {
    	n=getint(),m=getint();
    	for(register int i=1;i<=m;i++) {
    		x[i]=getint();
    		y[i]=getint();
    	}
    	reset();
    	for(register int i=1;i<=m;i++) {
    		s[x[i]].insert(y[i]);
    	}
    	for(register int i=1;i<=m;i++) {
    		cnt[i]+=query(x[i],y[i]);
    	}
    	reset();
    	for(register int i=1;i<=m;i++) {
    		s[y[i]].insert(x[i]);
    	}
    	for(register int i=1;i<=m;i++) {
    		cnt[i]+=query(y[i],x[i]);
    	}
    	reset();
    	for(register int i=1;i<=m;i++) {
    		s[x[i]+y[i]].insert(y[i]);
    	}
    	for(register int i=1;i<=m;i++) {
    		cnt[i]+=query(x[i]+y[i],y[i]);
    	}
    	reset();
    	for(register int i=1;i<=m;i++) {
    		s[x[i]-y[i]+n].insert(y[i]);
    	}
    	for(register int i=1;i<=m;i++) {
    		cnt[i]+=query(x[i]-y[i]+n,y[i]);
    	}
    	for(register int i=1;i<=m;i++) {
    		t[cnt[i]]++;
    	}
    	for(register int i=0;i<=8;i++) {
    		printf("%d%c",t[i]," 
    "[i==8]);
    	}
    	return 0;
    }
    

    ladder

    题目大意:

    最开始有(4)个梯子,高度都为(n(nle1000)),也就是每个梯子都有(n)层脚蹬的横木。小明想要对梯子进行改造(撤掉一些脚蹬用的横木),要满足以下两个条件。

    1. 撤掉一些横木之后,要保证每一层(4)个梯子中有且仅有(1)个梯子在这一层是有横木的。
    2. 梯子上面连向房顶,小明希望存在至少一个梯子能通过它爬到房顶(不能爬的过程中转换梯子),其中小明每次能至多爬(h(hle30))的高度,也就是从地面上(地面高度为(0))可以达到高度为(1sim h)的横木上,以及只可以从(n-h+1sim n)高度的横木上爬到房顶(房顶高度为(n+1))上去。

    也就是说在撤掉一些横木之后,要求存在一个梯子,它的剩下的第一个横木是不超过(h)的高度,剩下的最后一个横木是大于等于(n-h+1)的高度,中间的任意两个相邻剩下的横木之间相差高度不超过(h)

    小明现在想知道满足条件的撤横木的方案数,答案对(10^9+9)取模。 其中两个方案不同当且仅当:存在某一层在两个方案当中,他们各自保留的那一根横木在不同的梯子上。

    思路:

    (f[i][dis_1][dis_2][dis_3][dis_4])表示考虑完前(i)个位置,(dis_j)表示第(j)个梯子上最上面的踏板到当前位置的距离。

    这样是(mathcal O(nh^4))的。

    考虑要保证有一个梯子是可以登顶的,因此我们可以用(f[i][0/1][dis_2][dis_3][dis_4])表示前(i)个位置,第(1)个梯子是否是通的,(dis_j)与之前的状态相同。

    显然(4)个梯子是平等的,因此最后将答案( imes4)

    时间复杂度(mathcal O(nh^3))

    源代码:

    #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;
    }
    typedef long long int64;
    const int N=1001,M=31,mod=1e9+9;
    int f[N][2][M][M][M];
    inline void inc(int &x,const int &y) {
    	(x+=y)%=mod;
    }
    int main() {
    	const int n=getint(),m=getint();
    	f[1][1][1][1][1]=1;
    	for(register int i=1;i<n;i++) {
    		for(register int j=1;j<=m;j++) {
    			for(register int k=1;k<=m;k++) {
    				for(register int l=1;l<=m;l++) {
    					inc(f[i+1][1][std::min(j+1,m)][std::min(k+1,m)][std::min(l+1,m)],f[i][1][j][k][l]),
    					inc(f[i+1][0][std::min(j+1,m)][std::min(k+1,m)][std::min(l+1,m)],f[i][0][j][k][l]);
    					inc(f[i+1][j<m][1][std::min(k+1,m)][std::min(l+1,m)],f[i][1][j][k][l]);
    					inc(f[i+1][j<m][m][std::min(k+1,m)][std::min(l+1,m)],f[i][0][j][k][l]);
    					inc(f[i+1][k<m][std::min(j+1,m)][1][std::min(l+1,m)],f[i][1][j][k][l]),
    					inc(f[i+1][k<m][std::min(j+1,m)][m][std::min(l+1,m)],f[i][0][j][k][l]);
    					inc(f[i+1][l<m][std::min(j+1,m)][std::min(k+1,m)][1],f[i][1][j][k][l]),
    					inc(f[i+1][l<m][std::min(j+1,m)][std::min(k+1,m)][m],f[i][0][j][k][l]);
    				}
    			}
    		}
    	}
    	int ans=0;
    	for(register int i=1;i<=m;i++) {
    		for(register int j=1;j<=m;j++) {
    			for(register int k=1;k<=m;k++) {
    				(ans+=f[n][0][i][j][k])%=mod;
    				(ans+=f[n][1][i][j][k])%=mod;
    			}
    		}
    	}
    	ans=(ans-f[n][0][m][m][m]+mod)%mod;
    	ans=(int64)ans*4%mod;
    	printf("%d
    ",ans);
    	return 0;
    }
    

    color

    题目大意:

    给定一串(n)个珠子,其中每一个珠子的颜色为(a_i),总共有(k)类颜色珠子标号从(1)(k)

    初始给定一个参数(T)。询问再给定(m)个区间(l_i)(r_i),每次询问这个区间有多少颜色的珠子出现了恰好(T)次。

    (n,m,k,Tle5 imes10^5)

    思路:

    将询问离线,枚举右端点。新加入一个右端点(r)时,假设离(r)(t)近的同色位置为(q),第(t+1)近的是(q),则当(r)是右端点时,((p,q])的点都可以作为左端点,线段树维护即可。

    时间复杂度(mathcal O((n+m)log n))

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<vector>
    #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=5e5+1,M=5e5;
    int a[N],ans[M];
    struct Query {
    	int l,r,id;
    	bool operator < (const Query &rhs) const {
    		return r<rhs.r;
    	}
    };
    Query q[M];
    std::vector<int> v[N];
    class SegmentTree {
    	#define _left <<1
    	#define _right <<1|1
    	#define mid ((b+e)>>1)
    	private:
    		int val[N<<2];
    	public:
    		void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const int &v) {
    			if(b==l&&e==r) {
    				val[p]+=v;
    				return;
    			}
    			if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r),v);
    			if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r,v);
    		}
    		int query(const int &p,const int &b,const int &e,const int &x) const {
    			int ret=val[p];
    			if(b==e) return ret;
    			if(x<=mid) ret+=query(p _left,b,mid,x);
    			if(x>mid) ret+=query(p _right,mid+1,e,x);
    			return ret;
    		}
    	#undef _left
    	#undef _right
    	#undef mid
    };
    SegmentTree sgt;
    int main() {
    	const int n=getint(),m=getint(),k=getint(),t=getint();
    	for(register int i=1;i<=k;i++) v[i].push_back(0);
    	for(register int i=1;i<=n;i++) a[i]=getint();
    	for(register int i=0;i<m;i++) {
    		q[i].l=getint();
    		q[i].r=getint();
    		q[i].id=i;
    	}
    	std::sort(&q[0],&q[m]);
    	for(register int i=1,j=0;i<=n;i++) {
    		const int tmp=v[a[i]].size();
    		v[a[i]].push_back(i);
    		if(tmp>=t+1) sgt.modify(1,1,n,v[a[i]][tmp-t-1]+1,v[a[i]][tmp-t],-1);
    		if(tmp>=t) sgt.modify(1,1,n,v[a[i]][tmp-t]+1,v[a[i]][tmp-t+1],1);
    		for(;j<m&&q[j].r==i;j++) ans[q[j].id]=sgt.query(1,1,n,q[j].l);
    	}
    	for(register int i=0;i<m;i++) {
    		printf("%d
    ",ans[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    shell script数组使用函数输出
    Yii2文件上传
    ubuntu 安装遇到黑屏
    使用函数
    ionCube 安装
    记录LNMP环境彻底删除绑定域名及网站文件夹/文件的过程
    lnmp环境 开启pathinfo
    国外知名设计教程网址收集
    26个国外在线教育网站
    前端学习网站汇总
  • 原文地址:https://www.cnblogs.com/skylee03/p/9693042.html
Copyright © 2020-2023  润新知