1. 程式人生 > 其它 >CSP 後多校十四(拉格朗日待補)

CSP 後多校十四(拉格朗日待補)

「構造字串·尋寶·序列·構樹 」

A. 構造字串

複雜度為 \(O(n^2)\) 及以上的時候還是很好想的,不過這題資料過水,\(O(n^2)\) 隨便寫.

考慮怎麼優化,不難發現每個關係之間形成了類似於圖之間的關係.

於是倍增就可以了,不過題解裡寫了一個字符集大小的限制,沒太懂,希望有會的 dalao 能來踹我.

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
	// #define int long long
	#define lf double 
	#define pb push_back
	#define mp make_pair
	#define lb lower_bound
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof(x))
	#define Copy(x,y) memset(x,y,sizeof(x))
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
		while(!isdigit(ch)) cit|=(ch=='-'),ch=getchar();
		while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
		return cit?(-w):w;
	};
}using namespace BSS;

const int N=1e3+21;

int m,n;
int fa[N],col[N],vis[N];
vector<int> vec,emp[N];
int find(int x){ return fa[x]==x ? x : fa[x]=find(fa[x]); }
signed main(){
	File(str);
	n=read(),m=read(); int x,y,z;
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=m;i++){
		x=read(),y=read(),z=read();
		for(int j=1;j<=z;j++){
			fa[find(x+j-1)]=find(y+j-1);
		}
		emp[x+z].pb(y+z),emp[y+z].pb(x+z);
	}
	for(int i=1;i<=n;i++){
		if(find(i)==i) continue;
		for(auto j : emp[i]) emp[find(i)].pb(j);
	}
	for(int i=1;i<=n;i++){
		for(auto j : emp[i]){
			if(find(i)==find(j)) puts("-1"),exit(0);
		}
	}
	Fill(col,-1);
	for(int i=1;i<=n;i++){
		if(~col[i]) continue;
		x=0;
		for(auto j : emp[find(i)]){
			if(~col[j]){
				vec.pb(col[j]),x=max(x,col[j]),vis[col[j]]=1;
			}
		}
		for(int j=0,lmj=x+1;j<=lmj;j++){
			if(!vis[j]){
				col[i]=j; break;
			}
		}
		for(int j=i;j<=n;j++){
			if(find(i)==find(j)) col[j]=col[i];
		}
		for(int j=0,lmj=x+1;j<=lmj;j++) vis[j]=0;
	}
	for(int i=1;i<=n;i++) printf("%d ",col[i]);
	exit(0);
}

B. 尋寶

簡單題,複雜度沒卡 \(bitset\),不過 \(O(k^3)\) 傳遞閉包也是可以的.

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
	// #define int long long
	#define lf double 
	#define pb push_back
	#define mp make_pair
	#define lb lower_bound
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof(x))
	#define Copy(x,y) memset(x,y,sizeof(x))
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
		while(!isdigit(ch)) cit|=(ch=='-'),ch=getchar();
		while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
		return cit?(-w):w;
	};
}using namespace BSS;

#define y0 assa
#define y1 asas
#define y2 sasa
#define merge asasasas

const int N=1e5+21,M=1e5+21;

char ch[N];
int m,n,ms,ns,ts,cnt,tot;
int id[N],fa[N],head[N],ans[N],pos[N],vis[N],ru[N];
int find(int x){ return x==fa[x] ? x : fa[x]=find(fa[x]) ; }
vector<int> mg[N],rk[N];
bitset<M> con[M];
struct I { int u,v,nxt; } e[N<<1];
auto add=[](int u,int v)->void{
	e[++ts].u=u,e[ts].v=v,e[ts].nxt=head[u];
	head[u]=ts,ru[u]++;
};
auto merge=[](int i,int j)->void{
	fa[find(i)]=find(j);
};
queue<int> que;
auto bfs=[]()->void{
	for(int i=1;i<=tot;i++) que.push(i),con[i].set(i,1),vis[i]=1;
	while(que.size()){
		int u=que.front(); que.pop();
		for(int i=head[u];i;i=e[i].nxt){
			if(con[u]==con[e[i].v]) continue;
			con[e[i].v]|=con[u];
			if(!vis[e[i].v]) que.push(e[i].v);
			vis[e[i].v]=1;
		}
		vis[u]=0;
	}
};
signed main(){
	File(treasure);
	n=read(),m=read(),ms=read(),ns=read();
	for(int i=0,lmi=m+1;i<=lmi;i++){
		mg[0].pb(0),rk[0].pb(0);
		mg[n+1].pb(0),rk[n+1].pb(0);
	}
	for(int i=1;i<=n;i++){
		scanf("%s",ch+1),mg[i].pb(0);
		for(int j=1;j<=m;j++) mg[i].pb(ch[j]=='.');
		mg[i].pb(0);
	}
	// for(int i=1;i<=n;i++){
	// 	for(int j=1;j<=m;j++) cout<<mg[i][j]<<' ' ;
	// 	puts("");
	// }
	for(int i=1;i<=n;i++){
		rk[i].pb(0);
		for(int j=1;j<=m;j++) rk[i].pb(++cnt),fa[cnt]=cnt;
		rk[i].pb(0);
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(!mg[i][j]) continue;
			if(mg[i][j-1]) merge(rk[i][j],rk[i][j-1]);
			if(mg[i-1][j]) merge(rk[i][j],rk[i-1][j]);
			if(mg[i][j+1]) merge(rk[i][j],rk[i][j+1]);
			if(mg[i+1][j]) merge(rk[i][j],rk[i+1][j]);
		}
	}
	int x,y,x1,y1,x2,y2,res;
	for(int i=1;i<=cnt;i++){
		if(find(i)==i) id[i]=++tot,pos[tot]=i;
	}
	for(int i=1;i<=ms;i++){
		x1=read(),y1=read(),x2=read(),y2=read();
		add(id[find(rk[x2][y2])],id[find(rk[x1][y1])]);
	}
	bfs();
	for(int i=1;i<=ns;i++){
		x1=read(),y1=read(),x2=read(),y2=read();
		x=find(rk[x1][y1]),y=find(rk[x2][y2]);
		res=con[id[x]][id[y]]|(x==y),printf("%d \n",res);
	}
	exit(0);
}

C. 序列

顯然和斜率有關,推著推著腦子就熱了,於是就沒打出來.

李超線段樹確實是很好用的,不過感覺 \(O(nlogn)\)\(CDQ\) 也能寫,由於懶,就沒打.

C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
	#define int long long
	#define lf double 
	#define pb push_back
	#define mp make_pair
	#define lb lower_bound
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof(x))
	#define Copy(x,y) memset(x,y,sizeof(x))
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
		while(!isdigit(ch)) cit|=(ch=='-'),ch=getchar();
		while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
		return cit?(-w):w;
	};
}using namespace BSS;

#define ls (x<<1)
#define rs (x<<1|1)
const int N=1e6+21,inf=1e15,C=1e6+1,W=2e6+1;

int m,n;
int a[N],b[N],pa[N],pb[N],ans[N];
struct II { int x,y,id; } q[N];
struct I{
	int k,b;
	I(){}
	I(int k_,int b_) : k(k_),b(b_) {}
	inline int calc(int x){ return k*(x-C)+b; }
}tr[W<<3];
void build(int x,int l,int r){
	tr[x].k=inf,tr[x].b=inf; if(l==r) return ;
	int mid=(l+r)>>1; 
	build(ls,l,mid),build(rs,mid+1,r);
}
void ins(int x,int l,int r,I px){
	if(px.k==inf) return ;
	if(tr[x].k==inf or (px.calc(l)<tr[x].calc(l) and px.calc(r)<tr[x].calc(r) )){
		return tr[x]=px,void();
	}
	int mid=(l+r)>>1; 
	if(tr[x].k==inf or tr[x].calc(mid)>px.calc(mid)) swap(px,tr[x]);
	if(tr[x].calc(l)>px.calc(l)) ins(ls,l,mid,px);
	if(tr[x].calc(r)>px.calc(r)) ins(rs,mid+1,r,px);
}		
int qry(int x,int l,int r,int px){
	if(l==r) return (tr[x].k==inf ? inf : tr[x].calc(px));
	int mid=(l+r)>>1,res=(tr[x].k==inf ? inf : tr[x].calc(px));
	if(px<=mid) res=min(res,qry(ls,l,mid,px));
	else res=min(res,qry(rs,mid+1,r,px));
	return res;
}
auto solve=[](int i)->void{
	// cout<<q[i].id<<" "<<pa[q[i].x]+pb[q[i].x]*q[i].y<<' '<<qry(1,1,W,q[i].y+C)<<' '<<q[i].y<<" skr\n";
	ans[q[i].id]+=pa[q[i].x]+pb[q[i].x]*q[i].y-qry(1,1,W,q[i].y+C);
};
auto Work=[]()->void{
	build(1,1,W),ins(1,1,W,I(0,0));
	sort(q+1,q+1+m,[](II i,II j){ return i.x<j.x; });
	for(int i=1;i<=n;i++) pa[i]=pa[i-1]+a[i],pb[i]=pb[i-1]+b[i];
	for(int i=1,j=1;i<=n;i++){
		while(j<=m and q[j].x==i) solve(j),j++;
		ins(1,1,W,I(pb[i],pa[i]));
	}
};
signed main(){
	File(seq);
	n=read(),m=read(); int x,y;
	for(int i=1;i<=n;i++) a[i]=read(),b[i]=read();
	for(int i=1;i<=m;i++) q[i].x=read(),q[i].y=-read(),ans[i]-=a[q[i].x]+b[q[i].x]*q[i].y,q[i].id=i;
	Work();
	for(int i=1;i<=m;i++) q[i].x=n-q[i].x+1;
	reverse(a+1,a+1+n),reverse(b+1,b+1+n);
	Work();
	for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
	exit(0);
}

D. 構樹

拉格朗日,鴿了.