10.13NOIP模拟赛

T1 魔界大门

题意:

小蛮,龙幽,姜云凡拜入蜀山门下,多日之后闲来无事,忽然想去魔界查访神农鼎的下落,当他们到魔界大门时,却被守门卫士执宿,疚业拦住,无奈之中只能开打,胜利之后卫士消失,魔界大门却迟迟没有动静,这是眼尖的小蛮发现门上有许多的数字,门的上方写着0/1,懂得魔族语言的龙幽反复观察门上的文字,发现门上给出的是三个N*N 的矩阵A,B,C,当A*B=C 他们只要把门上的1全部按下去就能打开大门,否则需要按下所有的0。四个人的数学都不好,所以请你帮助他们判断A*B 是否与C 相等。

提示:矩阵乘法+随机化

考试的时候memset写错导致丢掉暴力40分QAQ

算法1:暴力矩阵乘法 期望得分40

但是O(n^3)算法铁定超时,所以我们想一想,为什么要全算完呢?

算法2:随机化坐标 我们可以rand()矩阵中的坐标,只计算这么一个坐标,之后与目标矩阵中的对应点比较,相同继续rand,不同直接跳出,但是也不能一直算,所以期望得分70~80

既然可以随机化坐标,那为什么不能随机化矩阵呢?

算法3:随机化矩阵 我们一次rand出一个n*1的矩阵,之后乘,每次O(n^2)效率,随机2~3次即可解决,期望得分100

 

#include
#include
#include

using namespace std;

const int MAXN=1020;

unsigned int T,n,a[MAXN][MAXN],b[MAXN][MAXN],c[MAXN][MAXN],d[MAXN][MAXN];
unsigned int A[MAXN][MAXN],B[MAXN][MAXN],C[MAXN][MAXN],t[MAXN];

bool init() {
    memset(A,0,sizeof(A));
	memset(B,0,sizeof(B));
	memset(d,0,sizeof(d));
	int i,j,k;
	scanf("%d",&n);
	for(i=1;i<=n;++i)
	    for(j=1;j<=n;++j)
	        scanf("%d",&a[i][j]);
	for(i=1;i<=n;++i)
	    for(j=1;j<=n;++j)
	        scanf("%d",&b[i][j]);
	for(i=1;i<=n;++i)
	    for(j=1;j<=n;++j)
	        scanf("%d",&c[i][j]);
	for(i=1;i<=n;++i){
			 t[i]=rand()%100;
	}
	for(i=1;i<=1;++i){
		for(j=1;j<=n;++j){
		    for(k=1;k<=n;++k){
				A[i][j]+=t[k]*a[k][j];
			}
		}
	}
	for(i=1;i<=1;++i){
		for(j=1;j<=n;++j){
		    for(k=1;k<=n;++k){
		        B[i][j]+=A[i][k]*b[k][j];
			}
		}
	}
    for(i=1;i<=1;++i){
		for(j=1;j<=n;++j){
		    for(k=1;k<=n;++k){
		        d[i][j]+=t[k]*c[k][j];
			}
			if(d[i][j]!=B[i][j])
				return 0;
		}
	}
	return 1;
}

int main(){
	scanf("%d",&T);
	while(T--) {
		if(init()) printf("TRUE\n");
		else printf("FALSE\n");
	}
}


T2 糖果

题意:

小姜找到了童话中“糖果国”,这里大到摩天大厦,小到小花小草都是用糖果建造而成的。更加神奇的是,天空中飘满了五颜六色的糖果云,很快糖果雨密密麻麻从天而落,红色的是草莓糖,黄色的是柠檬糖,绿色的是薄荷糖,黑色的是巧克力糖……

任何时候天空中所有的云朵颜色都不相同,不同颜色的云朵在不断地落下相应颜色的糖果。小姜发现天空中会不断出现一些云朵,而有的云朵在某一时刻又会自动消失,而云朵在存在时会不断地落下相应颜色的糖果,小姜有许多容量无限且袋口宽度不同的口袋,小姜完全接到一种糖果,当且仅当下落该种糖果的那朵云被袋口完全包含,小姜想知道每次他拿出一个袋口为[L,R]的口袋后他能完全接到多少种糖果。

提示:二维树状数组

考试的时候直接浮水法拿到暴力30分

算法1:浮水法 每当读入一个3区间,向上浮,能包住1区间就ans++,包住2区间ans—

算法2:观察数据特点,区间的范围较小,而区间[A,B]是区间[X,Y]的子集

的充要条件是X<=A<=Y 且X<=B<=Y,这样我们以区间左端点为X 轴坐标,以

区间右端点为Y 轴坐标,这样每个区间都唯一对应着平面上的一个点,以上三

种操作可以转化为删除平面上一个点,插入平面上一个点,查询一个矩形内点的

个数,可以用二维树状数组维护,时间复杂度O(m*logn*logn)

 

#include
#include
#include

using namespace std;

const int MAXN=1020;

int n;
int t[MAXN][MAXN];

void add(int x,int y,int d) {
	for(int i=x;i<=1015;i+=(i&(-i)))
	    for(int j=y;j<=1015;j+=(j&(-j)))
	        t[i][j]+=d;
}

int sum(int x,int y){
	int res=0;
	for(int i=x;i;i-=(i&(-i)))
	    for(int j=y;j;j-=(j&(-j)))
	        res+=t[i][j];
	return res;
}

int main(){
	int i,l,r,flag;
	scanf("%d",&n);
	for(i=1;i<=n;++i) {
		scanf("%d%d%d",&flag,&l,&r);
		if(flag==1) add(l,r,1);
		if(flag==2) add(l,r,-1);
		if(flag==3) printf("%d\n",sum(r,r)-sum(l-1,r));
	}
	return 0;
	
}


T3 sta

题意:给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大

考试A掉

提示:DP

算法:DP f[x]=f[fa[x]]+n-2*size[x] fa[x]为x父节点 size[x]指以x为根的子树大小

首先我们找到任意一个节点进行深搜,统计出每棵子树的大小,以及所有点的深度之和

然后再以该节点为根深搜一遍,此时状态从父节点转移至子节点,转移方程如下:

f[x]=f[fa[x]]+n-2*size[x]

最后扫一遍数组即可出解

 

#include
#include

using namespace std;

const int MAXN=1000010;
typedef long long LL;

int n,tot,ans;
int h[MAXN];
int fa[MAXN];
LL size[MAXN],f[MAXN];

struct Edge{
	int u,v,next;
}e[MAXN<<1];

void add(int u,int v) {
	e[++tot].u=u;
	e[tot].v=v;
	e[tot].next=h[u];
	h[u]=tot;
}

void dfs(int x) {
	size[x]=1;
	for(int i=h[x];i;i=e[i].next) {
		int v=e[i].v;
		if(v==fa[x]) continue;
		fa[v]=x;
		dfs(v);
		size[x]+=size[v];
		f[x]+=f[v]+size[v];
	}
}

void dp(int x) {
	if(x!=1)
		f[x]=f[fa[x]]+n-2*size[x];
	for(int i=h[x];i;i=e[i].next) {
		if(e[i].v==fa[x]) continue;
		dp(e[i].v);
	}
}

int main(){
	freopen("sta.in","r",stdin);
	freopen("sta.ans","w",stdout);
	int i,u,v;
	scanf("%d",&n);
	for(i=1;if[ans])
		   ans=i;
	printf("%d",ans);
}

   


 

T4 会议

提示:最短路

算法分析:很明显需要以地区为点,以结界为顶点之间的边且权值为1,这

样能够得到一个新图,目标也就是求新图中的一个点使某些点到这个点的距离和

最小,由于魔教精英在魔法点上,所以计算时要枚举他第一步在哪块地区内,取

最小值即可。

主要说下构图问题,对于相邻的两个地区,相邻结界的两个魔法点端点给出

的顺序一定相反,即一个是(A,B),另一个是(B,A)。所以只需扫描所有地区

的周围魔法点,一旦发现有两个魔法点顺序相反且相邻,则对应两个地区之间有

边。

 

#include
#include
#include

using namespace std;

const int MAXN=600;

int n,tot;
int vis[MAXN];
int peo[MAXN],h[MAXN];
int dis[MAXN][MAXN];
int barrier[MAXN][MAXN][5];
int area[MAXN][MAXN];

struct Edge{
	int u,v,w,next;
}e[MAXN<<2];

void add(int u,int v,int w) {
	e[++tot].u=u;
	e[tot].v=v;
	e[tot].w=w;
	e[tot].next=h[u];
	h[u]=tot;
}

void spfa(int x) {
	queueq;
	memset(vis,0,sizeof(vis));
	vis[x]=1;
	dis[x][x]=0;
	q.push(x);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=h[u];i;i=e[i].next) {
			int v=e[i].v;
			if(v>n&&dis[x][v]>dis[x][u]+e[i].w) {
				dis[x][v]=dis[x][u]+e[i].w;
				if(!vis[v]) {
					q.push(v);
					vis[v]=1;
				}
			}
		}
	}
}

void init(){
	int i,j,k;
	memset(dis,0x3f,sizeof(dis));
	scanf("%d%d%d",&area[0][0],&n,&peo[0]);
	for(i=1;i<=peo[0];++i) scanf("%d",&peo[i]);
	for(i=1;i<=area[0][0];++i) {
		scanf("%d",&area[i][0]);
		for(j=1;j<=area[i][0];++j) {
			scanf("%d",&area[i][j]);
			if(j!=1) {
				int p=area[i][j],q=area[i][j-1];
				barrier[p][q][++barrier[p][q][0]]=i;
				barrier[q][p][++barrier[q][p][0]]=i;
			}
			add(area[i][j],i+n,0);add(i+n,area[i][j],0);
		}
		int p=area[i][1],q=area[i][area[i][0]];
		barrier[p][q][++barrier[p][q][0]]=i;
		barrier[q][p][++barrier[q][p][0]]=i;
	}
	for(i=1;i<=n;++i)
	    for(j=1;j<=n;++j)
	        if(barrier[i][j][0]!=0) {
				add(barrier[i][j][1]+n,barrier[i][j][2]+n,1);
				add(barrier[i][j][2]+n,barrier[i][j][1]+n,1);
	        }
	for(i=1;i<=n;++i) spfa(i);
	int ans=0x3fffffff;
	int id=0;
	for(i=n+1;i<=area[0][0]+n;++i) {
		int temp=0;
		for(j=1;j<=peo[0];++j){
			temp+=dis[peo[j]][i];
		}
		if(ans>temp) {
			ans=temp;
			id=i-n;
		}
	}
	printf("%d\n%d",ans,id);
	while(1);
}

int main(){
	init();
}

你可能感兴趣的:(NOIP模拟)