【Matrica】【BST】【Najkraci】

【Matrica】

洛谷
模拟
首先,除了对角线以外都是两两对称的。
所以,如果有一个字母的个数为奇数,那么必须有一个放对角线上。
如果奇数字母的个数大于了nn(边长),就IMPOSSIBLE“IMPOSSIBLE”了。
数据三万,我们显然不能一个一个地填,只能求出询问列的字母就可以了。
由于填的的数要求沿对角线对称,所以只用求一半。
*****
__****
___***
_____**
______*
仅仅是单数填对角线可能不够,所以还要把几对的字母填入,而剩下的部分可以直接填,所以我们先填对角线。
先把字母排个序,求一下前缀和。
当前在第iiii列时,如果可以填双数的,且字母排序小,则连续填入两个,rr代表当前已经用了多少个(不算当前填的这个),这样用前缀和就可以判断排到哪个字母了。
注意,双数的一定是两个两个填,所以一开始我就除以了二,更新rr时,仔细推一推,不要算错了。
填完对角线后,把用过的数量都减去,再求一次前缀和。
同样的,填每一列时,我们都可以统计rr,算出每一位该填哪个字母,然后存入数组。
行小于列时,推一推更新rr
行等于列时,直接用之前算出的填入。
行大于列时,沿对角线对称,再推rr
注:注意卡常,registerregister把我从0.7s0.7s卡到了0.01s0.01s!!!

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=3e4+5;
#define re register 
int n,k,b[30],cnt=0,q,ans[N],u=0,e[51];
struct node{int v,num,sum;}a[30];
char s[4],c[N][51];
inline bool comp(const node &x,const node &y){
	return x.v<y.v;
}
int main(){
	n=read();k=read();
	for(re int i=1;i<=k;i++){
		scanf("%s",s);
		a[i].v=s[0]-'A';a[i].num=read();
		if(a[i].num%2){a[i].num--;b[++cnt]=a[i].v;u++;}
		a[i].num/=2;
	}
	if(u>n){printf("IMPOSSIBLE");return 0;}
	sort(a+1,a+k+1,comp);
	for(re int i=1;i<=k;i++)a[i].sum=a[i-1].sum+a[i].num;
	sort(b+1,b+cnt+1);
	for(re int i=1,r=0,use=(n-u)/2,n1=1,n2=1;i<=n;i++){
		while(a[n1].sum<=r&&n1<=k)n1++;
		if((n2<=cnt&&n1<=k&&b[n2]<=a[n1].v)||!use){ans[i]=b[n2++];r+=n-i;}
		else{ans[i]=ans[i+1]=a[n1].v;a[n1].num--;use--;r+=n-i+n-i;i++;}//
	} 
	for(re int i=1;i<=k;i++)a[i].sum=a[i-1].sum+a[i].num;
	q=read();
	for(re int i=1;i<=q;i++)e[i]=read();
	sort(e+1,e+q+1);
	for(re int i=1,x,r,n1;i<=q;i++){
		r=x=e[i];r-=2;n1=1;
		for(re int j=1;j<=x;j++){
			if(x==j){c[j][i]=(char)(ans[x]+'A');r++;continue;}
			while(a[n1].sum<=r)n1++;
			c[j][i]=(char)(a[n1].v+'A');
			r+=n-j-1;
		}
		for(re int j=x+1;j<=n;j++){
			while(a[n1].sum<=r)n1++;
			c[j][i]=(char)(a[n1].v+'A');
			r++;
		}
	}
	for(re int i=1;i<=n;i++){
		for(re int j=1;j<=q;j++)
			putchar(c[i][j]);
		putchar('\n');
	}
	return 0;
}

【BST】

洛谷
双向链表
容易发现,插入的数xxxx只会最终接在xx的前驱或后继的下一层,深度较大的那一个的儿子节点上。
可以用双向链表,倒序删除节点求之前的前驱后继。
详情看代码就懂了。

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=3e5+4;
int n,a[N],l[N],r[N],pre[N],nxt[N],dep[N];
long long ans=0;
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		a[i]=read();
		l[i]=i-1;r[i]=i+1;//模拟链表 
	}
	r[n]=0;dep[0]=-1;
	for(int i=n;i;i--){
		pre[a[i]]=l[a[i]];
		nxt[a[i]]=r[a[i]];//记录答案 
		r[l[a[i]]]=r[a[i]];
		l[r[a[i]]]=l[a[i]];//删除该节点,更新左右 
	}
	for(int i=1;i<=n;i++){
		dep[a[i]]=max(dep[pre[a[i]]],dep[nxt[a[i]]])+1;
		ans+=dep[a[i]];
		printf("%lld\n",ans);
	}
	return 0;
}

【Najkraci】

洛谷
最短路
拓扑排序
题目大意:给定一个NN个点MM条边的有向图。(点的编号从11NN)每条边上有权,表示边连接的两点间的距离(注意是有向边)。AA点到BB点的路径的长度为,所经过的所有边的权值之和。AABB的最短路为所有路径中长度最小的一个。
你的工作是对于每条边,输出有多少条最短路经过它。(结果对10000000071 000 000 007求余)
?洛谷数据有问题?

每一个点作为起点跑一遍dijdij,把最短路上的边重新建一个图,一定是DAGDAG,可以用拓扑排序。
f[i]f[i]:从起点到ii的最短路个数
g[ig[i]:从ii到其他点的最短路个数
对于边e[i]e[i],加上答案f[u]g[v]f[u]*g[v]
注意dijdij不要写错了,刚开始建的图不要和新建的DAGDAG搞错了。

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int mod=1e9+7,N=1505,M=5005;
int dis[N],vis[N],n,m,ans[M],fl[M],in[N];
struct edge{int u,v,w,nxt;}e[M*2],a[M*4];
int first[N],cnt=0,head[N];
inline void add(int u,int v,int w){
	e[++cnt].v=v;e[cnt].u=u;e[cnt].w=w;
	e[cnt].nxt=first[u];first[u]=cnt;
}
inline void add2(int u,int v,int w){
	a[++cnt].u=u;a[cnt].v=v;a[cnt].w=w;
	a[cnt].nxt=head[u];head[u]=cnt;
}
inline void dij(int s){
	priority_queue< pair<int,int> >q;
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	memset(fl,0,sizeof(fl));
	q.push(make_pair(0,s));//
	dis[s]=cnt=0;
	while(!q.empty()){
		int x=q.top().second;q.pop();
		if(vis[x])continue;
		vis[x]=1;
		for(int i=first[x],v;i;i=e[i].nxt){
			v=e[i].v;
			if(dis[v]>dis[x]+e[i].w){
				dis[v]=dis[x]+e[i].w;
				q.push(make_pair(-dis[v],v));
			}
		}
	}
}
int f[N],g[N];//s到i有多少种  i到其他有多少种   保证为DAG 
int main(){
	n=read();m=read();
	for(int i=1,u,v,w;i<=m;i++){
		u=read();v=read();w=read();
		add(u,v,w);
	}
	for(int i=1;i<=n;i++){
		dij(i);//要保存老图 
		memset(head,0,sizeof(head));
		memset(in,0,sizeof(in));
		for(int j=1;j<=m;j++)
			if(dis[e[j].u]+e[j].w==dis[e[j].v]){
				fl[j]=1;in[e[j].v]++;
				add2(e[j].u,e[j].v,e[j].w);
			}
		memset(f,0,sizeof(f));
		f[i]=1;
		queue<int>q;
		q.push(i);
		while(!q.empty()){
			int u=q.front();q.pop();
			for(int j=head[u],v;j;j=a[j].nxt){
				v=a[j].v;
				f[v]+=f[u];
				in[v]--;
				if(!in[v])q.push(v);
			}
		}
		memset(head,0,sizeof(head));
		memset(in,0,sizeof(in));
		for(int j=1,x=cnt;j<=x;j++){
			add2(a[j].v,a[j].u,a[j].w);
			in[a[j].u]++;
		}
		fill(g+1,g+n+1,1);
		for(int j=1;j<=n;j++)
			if(!in[j])q.push(j);
		while(!q.empty()){
			int u=q.front();q.pop();
			for(int j=head[u],v;j;j=a[j].nxt){
				v=a[j].v;
				g[v]+=g[u];
				in[v]--;
				if(!in[v])q.push(v);
			} 
		}
		for(int j=1;j<=m;j++)
			if(fl[j])ans[j]=(ans[j]+(long long)f[e[j].u]*g[e[j].v]%mod)%mod;
	}
	for(int i=1;i<=m;i++)
		printf("%d\n",ans[i]);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章