【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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章