XJOI CSP-S2 2019开放模拟训练题1 赛后总结

比赛链接

友好数对

暴力枚举\([L,R]\)之间的所有数,将每个数进行"旋转",看是否符合题意.

注意"旋转"的次数,并不一定是数字位数.只要旋转回到了初始数就应该跳出,否则会重复计算.

#include<bits/stdc++.h>
int T,L,R;

int F(int x)
{
	int Len=0;
	while(x){x/=10;Len++;}
	return Len;
}

int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&L,&R);
		int Len=F(L),p=1,Ans=0;
		for(int i=1;i<Len;i++)p*=10;
		for(register int A=L;A<=R;A++)
		{
			int B=A;
			while(1)
			{
				B=B/10+p*(B%10);
				if(A<B&&B<=R)++Ans;
				if(A==B)break;
			}	
		}
		printf("%d\n",Ans);	
	}	
	return 0;
} 

路径数

因为Euphemia对于美的追求,"她走过的路径是关于左下 - 右上对角线对称的",我们可以把把右下方一半的图对称到左上方,然后对于每个格子,向它可达的格子连边,再把左上 - 右下对角线上的格子向超级汇点连边,跑一边Dijkstra同时计算最短路条数即可.

但是开始的时候,我把对称那里写成了中心对称,导致爆0.😢

菜是原罪

#include<bits/stdc++.h>
const int SIZE=105,N_MAX=10005,M_MAX=80005,Mod=1000000009;
int n,G[SIZE][SIZE],P[SIZE][SIZE],R[N_MAX];
int head[N_MAX],nex[M_MAX],to[M_MAX],Tot;
void Link(int u,int v){nex[++Tot]=head[u];head[u]=Tot;to[Tot]=v;} 
int OFFX[]={0,-1,0,0,1},OFFY[]={0,0,-1,1,0};
bool E(int X,int Y){return (X<1||Y<1||X>n||Y>n||X+Y>n+1)? 0 : 1;}

struct node
{
	int pos,D;
	bool operator <(const node &x)const
	{
		return D>x.D;
	}
};
std::priority_queue<node>q;
bool mk[N_MAX];
int D[N_MAX],F[N_MAX];
void Dijkstra()
{
	memset(D,0x3F,sizeof(D));
	memset(F,0,sizeof(F));
	memset(mk,0,sizeof(mk));
	D[1]=R[1];
	F[1]=1;
	q.push((node){1,D[1]});
	while(q.size())
	{
		int u=q.top().pos;
		q.pop();
		if(mk[u])continue;
		mk[u]=1;
		for(int i=head[u];i;i=nex[i])
		{
			int v=to[i];
			if(D[v]>D[u]+R[v])
			{
				D[v]=D[u]+R[v];
				F[v]=F[u];
				q.push((node){v,D[v]});
			}
			else if(D[v]==D[u]+R[v])
				F[v]=(F[v]+F[u])%Mod;	
		}
	}
}

int main()
{
	while(1)
	{
		scanf("%d",&n);
		if(n==0)break;
		int Tim=0;
		memset(P,0,sizeof(P));
		for(int i=1;i<=n;i++)
			for(int k=1;k<=n;k++)
			{
				scanf("%d",&G[i][k]);
				P[i][k]=++Tim;
			}	
		++Tim;
		memset(R,0,sizeof(R));
		for(int i=1;i<=n;i++)
			for(int k=1;k+i<=n+1;k++)
			{
				if(k+i==n+1)R[P[i][k]]=G[i][k];
				else R[P[i][k]]=G[i][k]+G[n-k+1][n-i+1];
			}	
		memset(head,0,sizeof(head));
		Tot=0;
		for(int i=1;i<=n;i++)
			for(int k=1;k+i<=n+1;k++)
			{
				for(int p=1;p<=4;p++)
				{
					int Xs=i+OFFX[p];
					int Ys=k+OFFY[p];
					if(E(Xs,Ys))
						Link(P[i][k],P[Xs][Ys]);
				}
				if(k+i==n+1)
					Link(P[i][k],Tim);
			}
		Dijkstra();
		printf("%d\n",F[Tim]);
	}		
	return 0;
}

选信封

打了个DFS套DFS,获得了30分的好成绩.

然后写了个模拟退火,就过了?甚至都没有srand.

此时我的表情是:

模拟退火代码(LCT维护连通性):

#include<bits/stdc++.h>
const int SIZE=1500;
#define Random(x) (rand()%x+1)

int n,A[SIZE][5],B[SIZE][5],Tem[SIZE],Ans,now,Tot;

struct LCT
{
	int F[SIZE],C[SIZE][2];
	bool Tag[SIZE];
	#define LC(x) C[x][0]
	#define RC(x) C[x][1]
	bool NRoot(int x){return LC(F[x])==x||RC(F[x])==x;} 
	void Rev(int x){std::swap(LC(x),RC(x));Tag[x]^=1;}
	void push_down(int x){if(Tag[x]){if(LC(x))Rev(LC(x));if(RC(x))Rev(RC(x));Tag[x]=0;}}
	void Rotate(int x)
	{
		int u=F[x],v=F[u],k=(RC(u)==x),w=C[x][k^1];
		if(NRoot(u))C[v][RC(v)==u]=x;C[x][k^1]=u;C[u][k]=w;
		if(w)F[w]=u;F[u]=x;F[x]=v;
	}
	void push(int x){if(NRoot(x))push(F[x]);push_down(x);}
	void Splay(int x)
	{
		for(push(x);NRoot(x);Rotate(x))
			if(NRoot(F[x]))Rotate((LC(F[x])==x)^(LC(F[F[x]])==F[x])?x:F[x]);
	}
	void Access(int u){for(int v=0;u;u=F[v=u])Splay(u),RC(u)=v;}
	void MakeRoot(int x){Access(x);Splay(x);Rev(x);}
	int Find(int x){Access(x);Splay(x);while(LC(x)){push_down(x);x=LC(x);}Splay(x);return x;}
	void Split(int u,int v){MakeRoot(u);Access(v);Splay(v);}
	void Link(int u,int v){MakeRoot(u);if(Find(v)!=u)F[u]=v;}
	void Cut(int u,int v){MakeRoot(u);if(Find(v)==u&&F[v]==u&&!LC(v))F[v]=RC(u)=0;}
}T;

void SA()
{
	for(double Temperature=1000;Temperature>1e-14;Temperature*=0.99)
	{
		int p=Random(n),o=Random(2);
		if(T.Find(A[p][o])!=T.Find(B[p][o]))
		{
			++now;
			Ans=std::max(Ans,now);
			T.Link(A[p][o],B[p][o]);
		}
		else if(exp(((double)Ans-now)/Temperature)<(double)Random(RAND_MAX)/RAND_MAX)
		{
			T.Cut(A[p][o],B[p][o]);
		}
	}
}

int main()
{
	srand(time(0));
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d%d",&A[i][1],&B[i][1],&A[i][2],&B[i][2]);
		Tem[++Tot]=A[i][1];
		Tem[++Tot]=B[i][1];
		Tem[++Tot]=A[i][2];
		Tem[++Tot]=B[i][2];
	}
	std::sort(Tem+1,Tem+1+Tot);
	for(int i=1;i<=n;i++)
	{
		A[i][1]=std::lower_bound(Tem+1,Tem+1+Tot,A[i][1])-Tem;
		B[i][1]=std::lower_bound(Tem+1,Tem+1+Tot,B[i][1])-Tem;
		A[i][2]=std::lower_bound(Tem+1,Tem+1+Tot,A[i][2])-Tem;
		B[i][2]=std::lower_bound(Tem+1,Tem+1+Tot,B[i][2])-Tem;
	}
	SA();
	printf("%d",Ans);
	return 0;
} 

这个模拟退火很明显是错的,我也不知道为啥就A了😢.

posted @ 2019-11-04 21:05  TaylorSwift13  阅读(325)  评论(0编辑  收藏  举报