[CLYZ2017]day8

异色弧

image

solution

70分

\(Let's\;orz\) BearChild!

朗格拉姆计数

image

solution

60分

将环复制两遍,预处理出前\(i\)个数中比\(j\)大的数的个数 ,枚举\(a,b\),答案加上\(c\)的个数.

#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 5001
#define M 10001
using namespace std;
typedef long long ll;
//s[i][j]表示前i个数中比j大的数的个数 
ll ans;
int s[M][N],a[M],n;
inline int read(){
	int ret=0;char c=getchar();
	while(!isdigit(c))
		c=getchar();
	while(isdigit(c)){
		ret=(ret<<1)+(ret<<3)+c-'0';
		c=getchar();
	}
	return ret;
}
inline void Aireen(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		scanf("%d",&a[i]);
	for(int i=1;i<=n;++i)
		a[i+n]=a[i];
	for(int j=1;j<=n;++j)
		for(int i=1;i<=(n<<1);++i){
			s[i][j]=s[i-1][j];
			if(a[i]>j) ++s[i][j];
		}
	for(int i=1;i<=n;++i)
		for(int j=i;j<i+n;++j)
			if(a[j]>a[i]){
				ans+=(ll)(s[i+n-1][a[j]]-s[j][a[j]]);
			}
	printf("%lld\n",ans);
}
int main(){
	freopen("counter.in","r",stdin);
	freopen("counter.out","w",stdout);
	Aireen();
	fclose(stdin);
	fclose(stdout);
	return 0;
}

100分

三元组的形式为\(123,231,312\).
\(231=XX1-321\).
\(312=3XX-321\).
树状数组或线段树维护即可.

#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 200005
using namespace std;
typedef long long ll;
ll ans;
int a[N],s[N],g[N],fr[N],be[N],n;
inline int read(){
	int ret=0;char c=getchar();
	while(!isdigit(c))
		c=getchar();
	while(isdigit(c)){
		ret=(ret<<1)+(ret<<3)+c-'0';
		c=getchar();
	}
	return ret;
}
inline int lowbit(int x){
	return x&(-x);
}
inline void add(int k){
	for(int i=k;i<=n;i+=lowbit(i))
		++s[i];
}
inline int ask(int k){
	int ret=0;
	for(int i=k;i;i-=lowbit(i))
		ret+=s[i];
	return ret;
}
inline ll c(int k){
	return 1ll*k*(k-1)>>1ll;
} 
inline void Aireen(){
	n=read();
	for(int i=1;i<=n;++i){
		a[i]=read();g[a[i]]=i;
	}
	for(int i=1;i<=n;++i){
		fr[i]=ask(g[i]-1);
		be[i]=ask(n)-ask(g[i]);
		add(g[i]);
	}
	memset(s,0,sizeof(s));
	for(int i=n,f,b;i;--i){
		f=ask(g[i]-1);
		b=ask(n)-ask(g[i]);
		add(g[i]);
		ans+=1ll*fr[i]*b;//123
		ans+=c(be[i])-1ll*f*be[i];//312
		ans+=c(f)-1ll*f*be[i];//231 
	}
	printf("%lld\n",ans);
}
int main(){
	freopen("counter.in","r",stdin);
	freopen("counter.out","w",stdout);
	Aireen();
	fclose(stdin);
	fclose(stdout);
	return 0;
}

修路

image

solution

斯坦纳树

\(f[i][j]\)表示以\(i\)为根的树中,连通的节点的状态为\(j\)的最小/大权值.
\(f[i][j]=min\{f[i][l]+f[i][l^j]\}\),\(l\)\(j\)的子集.
\(f[i][j]=min\{f[k][j]+g[k][i]\}\),这可以用\(spfa\)\(dijkstra\)求解.

100分

用斯坦纳树求出\(f[\;][\;]\)数组.
如果在状态\(j\)中,\(i\)\(n-i+1\)\(j\)中或都不在\(j\)中,\(g[j]=min\{f[i][j]\}\)(保证\(i\)\(n-i+1\)连通).
\(g[i]=min\{g[j]+g[i^j]\}j\)\(i\)的子集\()\).

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define K 8
#define N 10005
#define M 20005
#define INF 10000000
#define min(a,b) a<b?a:b
using namespace std;
int nxt[M],to[M],w[M];
int f[N][1<<K],ff[1<<K],g[N],q[INF],h,t,n,m,k,d,cnt;
bool inq[N];
inline int read(){
	int ret=0;char c=getchar();
	while(!isdigit(c))
		c=getchar();
	while(isdigit(c)){
		ret=(ret<<1)+(ret<<3)+c-'0';
		c=getchar();
	}
	return ret;
}
inline void addedge(int x,int y,int z){
	nxt[++cnt]=g[x];g[x]=cnt;to[cnt]=y;w[cnt]=z;
}
inline void spfa(int k){
	int u;
	while(h<=t){
		u=q[h++];inq[u]=false;
		for(int i=g[u];i;i=nxt[i])
			if(f[u][k]+w[i]<f[to[i]][k]){
				f[to[i]][k]=f[u][k]+w[i];
				if(!inq[to[i]]){
					inq[to[i]]=true;q[++t]=to[i];
				}
			}
	} 
}
inline bool chk(int s){
	for(int i=1;i<=d;++i)
		if((bool)(s&(1<<i-1))^(bool)(s&(1<<k-i)))
			return false;
	return true;
}
inline void Aireen(){
	n=read();m=read();d=read();
	for(int i=1,x,y,w;i<=m;++i){
		x=read();y=read();w=read();
		addedge(x,y,w);addedge(y,x,w);
	}
	k=d<<1;
	for(int i=1;i<=n;++i)
		for(int j=0;j<(1<<k);++j)
			f[i][j]=INF;
	for(int i=1;i<=d;++i)
		f[i][1<<i-1]=f[n-i+1][1<<k-i]=0;
	for(int j=0;j<(1<<k);++j){
		h=1;t=0;
		for(int i=1;i<=n;++i){
			for(int l=j;l;l=(l-1)&j)
				f[i][j]=min(f[i][j],f[i][l]+f[i][j^l]);
			if(f[i][j]<INF){
				inq[i]=true;q[++t]=i; 
			}
		}
		spfa(j);
	}
	for(int j=0;j<(1<<k);++j){
		ff[j]=INF;
		if(chk(j)){
			for(int i=1;i<=n;++i)
				ff[j]=min(ff[j],f[i][j]); 
		}
	}
	for(int j=0;j<(1<<k);++j)
		for(int l=j;l;l=(l-1)&j)
			ff[j]=min(ff[j],ff[j^l]+ff[l]);
	if(ff[(1<<k)-1]==INF) puts("-1");
	else printf("%d\n",ff[(1<<k)-1]);
}
int main(){
	freopen("road.in","r",stdin);
	freopen("road.out","w",stdout);
	Aireen();
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2021-11-27 17:58  Aireen_Ye  阅读(28)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.