noip模拟24[matrix·block·graph]

noip模拟24 solutions

这果然是wzz的题,见题如见人,感觉自己好像浪费了一套好题,只拿了30pts

只有第一题有分,害,后面的暴搜程序没有打,第一题状压少写了一层循环

惨死了,最后一题好难,是队奶奶给我讲会的

T1 matrix

这个题真的很简单,考场一个小时的时候思路已经完全了,

为啥没切,就是手惨,

就是一个涉及到三层的状压,一看到数据范围10都不到,不是状压是啥???

维护\(f[i][j][k]\)表示第i层,覆盖状态为j,选择按钮的状态为k,注意覆盖状态和按钮不是一个东西

a[i]预处理原有的状态,g[i][j]预处理状态所需要的代价

然后一行一行的向下转移就行了,j中包含k的影响

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int 
const int N=11;
int n,m;
int a[N],c[N][N];
int f[N][1<<10][1<<10],g[N][1<<10],las[N][1<<10];
int ans=0x3f3f3f3f;
signed main(){
	scanf("%d%d",&n,&m);
	int bas=1<<m;
	for(re i=1;i<=n;i++){
		char x[N];
		scanf("%s",x);
		for(re j=0;j<m;j++){
			int tmp=x[j]-'0';
			a[i]|=(tmp<<j);
		}
	}
	for(re i=1;i<=n;i++){
		for(re j=0;j<m;j++)
			scanf("%d",&c[i][j]);
		//cout<<"i= "<<i<<" ";
		for(re j=0;j<bas;j++){
			int tmp=0;
			for(re k=0;k<10;k++)
				if(j&(1<<k))
					tmp+=c[i][k];
			g[i][j]=tmp;
			//cout<<j<<" "<<g[i][j]<<"   ";
		}
		//cout<<endl;
	}
	memset(f,0x3f,sizeof(f));
	for(re i=0;i<bas;i++)
		for(re j=0;j<bas;j++)
			f[0][i][j]=0;
	for(re i=0;i<n;i++){
		for(re j=0;j<bas;j++){
			for(re u=0;u<bas;u++){
				if((j|u)!=bas-1)continue;
				for(re k=0;k<bas;k++){
					if(f[i][j][k]==0x3f3f3f3f)continue;
					int tmp=u|((u<<1)&(bas-1))|(u>>1)|k|a[i+1];
					if(i==0)tmp=u|((u<<1)&(bas-1))|(u>>1)|a[i+1];
					f[i+1][tmp][u]=min(f[i+1][tmp][u],f[i][j][k]+g[i+1][u]);
				}
			}
		}
	}
	for(re i=0;i<bas;i++)ans=min(ans,f[n][bas-1][i]);
	printf("%d",ans);
}

T2 block

这个题就是难了我一下午的题吗???

我对着这个题硬刚,刚了好久,第一问非常好理解,第二问的线段树就非常的神

第一问就是先排序,一个一个向里插,你会发现,当前序列中的数都比他大

所以这个数插入的位置-1就是有多少个比它大的数,所以这样就可以有了多种方案

所有的方案数相乘就是最后的方案数,

注意相等的情况,按照key从小到大排序,因为可以保证你当前的比上一个放的更加靠后

这样的话,和他一样的一定在他前面,当前能放的位置直接向后移就好了

第二问的线段树做法和第一问完全没有关系,不要再向第一个思路想了

考虑转变key的含义,让他表示当前数前面能够放几个比他大的数,

所以我们每插入一个数,就吧value比他小的数的key--,这样当有一个数的key为1的时候

只能继续插入小于等于他的数,注意这两个的取等啊啊啊

我们就可以直接按照value从小到大,然后建立一颗普普通通的线段树,

维护字典序最小的点,单点修改,区间修改,区间查询,就完事了,

实现还是挺麻烦的,我调了好久呢

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int 
const int N=5e5+5;
const int mod=1e9+7;
int n;
struct node{
	int key,val;
	node(){}
	bool operator < (node x)const{
		if(val!=x.val)return val>x.val;
		return key<x.key;
	}
}sca[N];
bool cmp(node x,node y){
	if(x.val!=y.val)return x.val<y.val;
	return x.key<y.key;
}
int ans=1;
struct XDS{
	#define ls x<<1
	#define rs x<<1|1
	int val[N*4],key[N*4],now[N*4],who[N*4];
	int laz[N*4],mn[N*44];
	int mim(int x,int y){
		if(x==-1)return y;
		if(y==-1)return x;
		if(sca[x].key!=sca[y].key)return sca[x].key<sca[y].key?x:y;
		return sca[x].val<sca[y].val?x:y;
	}
	void pushup(int x){
		if(now[ls]<=now[rs])now[x]=now[ls],who[x]=who[ls];
		else now[x]=now[rs],who[x]=who[rs];
		mn[x]=mim(mn[ls],mn[rs]);
		return ;
	}
	void pushdown(int x){
		if(!laz[x])return ;
		laz[ls]+=laz[x];
		laz[rs]+=laz[x];
		now[ls]+=laz[x];
		now[rs]+=laz[x];
		laz[x]=0;
		return ;
	}
	void build(int x,int l,int r){
		if(l==r){
			//if(sca[l].key==17&&sca[l].val==4)cout<<x<<endl;
			val[x]=sca[l].val;
			key[x]=sca[l].key;
			now[x]=key[x];
			who[x]=l;
			mn[x]=l;
			return ;
		}
		int mid=l+r>>1;
		build(ls,l,mid);
		build(rs,mid+1,r);
		pushup(x);return ;
	}
	void change(int x,int l,int r,int pos){
		if(l==r){
			//if(sca[l].key==17&&sca[l].val==4)cout<<x<<endl;
			key[x]=0x3f3f3f3f;
			now[x]=0x3f3f3f3f;
			mn[x]=-1;
			return ;
		}
		pushdown(x);
		int mid=l+r>>1;
		if(pos<=mid)change(ls,l,mid,pos);
		else change(rs,mid+1,r,pos);
		pushup(x);return ;
	}
	void ins(int x,int l,int r,int ql,int qr){
		if(ql>qr)return ;
		if(ql<=l&&r<=qr){
			laz[x]-=1;
			now[x]-=1;
			return ;
		}
		pushdown(x);
		int mid=l+r>>1;
		if(ql<=mid)ins(ls,l,mid,ql,qr);
		if(qr>mid)ins(rs,mid+1,r,ql,qr);
		pushup(x);return ;
	}
	int query(int x,int l,int r,int ql,int qr){
		if(qr<ql)return -1;
		if(ql<=l&&r<=qr)return mn[x];
		pushdown(x);
		int mid=l+r>>1,ret=-1;
		if(ql<=mid)ret=mim(ret,query(ls,l,mid,ql,qr));
		if(qr>mid)ret=mim(ret,query(rs,mid+1,r,ql,qr));
		pushup(x);
		return ret;
	}
	#undef ls
	#undef rs
}xds;
int fro[N],beh[N];
signed main(){
	scanf("%d",&n);
	for(re i=1;i<=n;i++)scanf("%d%d",&sca[i].key,&sca[i].val);
	sort(sca+1,sca+n+1);
	int sum;
	for(re i=1;i<=n;i++){
		if(sca[i].val==sca[i-1].val){
			ans=1ll*ans*min(i,sca[i].key+sum)%mod;
			sum++;
		}
		else {
			ans=1ll*ans*min(i,sca[i].key)%mod;
			sum=1;
		}
	}
	//cout<<"sb"<<endl;
	sort(sca+1,sca+n+1,cmp);
	for(re i=1;i<=n;i++){
		if(sca[i].val==sca[i-1].val)fro[i]=fro[i-1];
		else fro[i]=i-1,beh[i-1]=i;
	}
	for(re i=n;i>=1;i--)if(!beh[i])beh[i]=beh[i+1];
	beh[n]=n;
	printf("%d\n",ans);
	//cout<<"sb"<<endl;
	//sort(sca+1,sca+n+1,cmp);
	//cout<<sca[1].key<<" "<<sca[1].val<<endl;
	xds.build(1,1,n);
	//cout<<"finish build"<<endl;
	for(re i=1;i<=n;i++){
		int tmp;
		//cout<<sca[xds.who[1]].key<<" "<<xds.who[1]<<endl;
		if(xds.now[1]==1)tmp=xds.query(1,1,n,1,beh[xds.who[1]]);
		else tmp=xds.mn[1];
		//cout<<"query"<<endl;
		printf("%d %d\n",sca[tmp].key,sca[tmp].val);
		xds.change(1,1,n,tmp);
		//cout<<"change"<<endl;
		xds.ins(1,1,n,1,fro[tmp]);
		//cout<<"ins"<<endl;
	}
}

T3 graph

这个题,我跨越了三天才完成

就是先按照分层图的思路跑一边最短路,得到\(dis[n][j]\)表示1到n经过j条x边的最小距离

有啥用呢?我们用到的只有n,你会发现这个j的范围只有m,所以我们对于每一个

都去解一个不等式,\(m^2\),没错就是这个复杂度,不会爆炸,

解出来一个范围,看看有没有解,拿着左边界带进去,再跑个最短路

从1和n分别跑一遍,然后判断是不是在这个最短路上,不会炸不会炸

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define int long long
const int N=1005;
const int M=2005;
const int inf=0x3f3f3f3f3f3f3f3f;
int n,m,sum;
int to[M*2],nxt[M*2],val[M*2],head[N],rp;
void add_edg(int x,int y,int z){
	to[++rp]=y;
	val[rp]=z;
	nxt[rp]=head[x];
	head[x]=rp;
}
int dio[N][M];
bool vis[N][M];
struct node{
	int dit,now,num;
	node(){}
	node(int x,int y,int z){
		dit=x;now=y;num=z;
	}
	bool operator < (node x)const{
		return dit>x.dit;
	}
};
priority_queue<node> q;
void DIO(){
	memset(vis,false,sizeof(vis));
	memset(dio,0x3f,sizeof(dio));
	dio[1][0]=0;
	q.push(node(0,1,0));
	while(!q.empty()){
		int dit=q.top().dit;
		int now=q.top().now;
		int num=q.top().num;q.pop();
		if(vis[now][num])continue;
		//cout<<dit<<" "<<now<<" "<<num<<endl;
		vis[now][num]=true;
		for(re i=head[now];i;i=nxt[i]){
			int y=to[i];
			if(val[i]==-1){
				if(vis[y][num+1])continue;
				if(dio[y][num+1]>dit&&num<=sum){
					dio[y][num+1]=dit;
					q.push(node(dio[y][num+1],y,num+1));
				}
			}
			else {
				if(vis[y][num])continue;
				if(dio[y][num]>dit+val[i]&&num<=sum){
					dio[y][num]=dit+val[i];
					q.push(node(dio[y][num],y,num));
				}
			}
		}
	}
}
int dij[2][N];
bool via[N];
void DIJ(int x,int w,int h){
	memset(via,false,sizeof(via));
	dij[w][h]=0;
	q.push(node(0,h,0));
	while(!q.empty()){
		int dit=q.top().dit;
		int now=q.top().now;q.pop();
		if(via[now])continue;
		via[now]=true;
		for(re i=head[now];i;i=nxt[i]){
			int y=to[i];
			if(val[i]==-1){
				if(dij[w][y]<=dit+x)continue;
				dij[w][y]=dit+x;
				q.push(node(dit+x,y,0));
			}
			else{
				if(dij[w][y]<=dit+val[i])continue;
				dij[w][y]=dit+val[i];
				q.push(node(dit+val[i],y,0));
			}
		}
	}
}
bool pd[N];
signed main(){
	scanf("%lld%lld",&n,&m);
	for(re i=1,x,y,z;i<=m;i++){
		scanf("%lld%lld%lld",&x,&y,&z);
		add_edg(x,y,z);
		add_edg(y,x,z);
		if(z==-1)sum++;
	}
	DIO();
	for(re i=0;i<=sum;i++){
		if(dio[n][i]==inf)continue;
		//cout<<dio[n][i]<<endl;
		int le=inf,ge=0,flag=0;
		for(re j=0;j<=sum;j++){
			if(i==j)continue;
			int x=dio[n][j]-dio[n][i];
			int y=i-j;
			if(x<=0&&y>0){
				flag=1;break;
			}
			if(x>0&&y<0){
				continue;
			}
			//cout<<x<<" "<<y<<endl;
			if(x==0){
				if(y>0)le=min(le,0ll);
				else ge=max(ge,0ll);
			}
			else if(x<0&&y<0){
				x=-x;y=-y;
				int tmp=x/y;
				if(x%y)tmp++;
				ge=max(ge,tmp);
			}
			else{
				int tmp=x/y;
				le=min(le,tmp);
			}
		}
		//cout<<ge<<" "<<le<<" "<<dio[n][i]<<endl;
		if(flag==1||ge>le)continue;
		//cout<<"sb"<<endl;
		memset(dij,0x3f,sizeof(dij));
		DIJ(ge,0,1);DIJ(ge,1,n);
		int tmp=ge*i+dio[n][i];
		for(re i=2;i<n;i++){
			//cout<<dij[0][i]<<" "<<dij[1][i]<<endl;
			if(dij[0][i]+dij[1][i]==tmp)
				pd[i]=true;
		}
	}
	pd[1]=true;pd[n]=true;
	for(re i=1;i<=n;i++)
		if(pd[i])printf("1");
		else printf("0");
}
posted @ 2021-07-28 06:30  fengwu2005  阅读(101)  评论(0)    收藏  举报