【比赛报告】2018.10.11校赛[Nescafé 17] NOIP练习赛卷十三

比赛时间:2018.10.11 选手:lrllrl 得分:100+100+0=200 用时:2小时


A.黑魔法师之门

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


最初以为是求欧拉回路的数量,后来发现不可做,再后来发现了规律。
在这里插入图片描述

#include<cstdio>
#include<cstring>
const int N=2e5+10,mod=1e9+9;
int n,m,ans=1,f[N];
inline int findf(int x){return f[x]==x?x:f[x]=findf(f[x]);}
int main()
{
	freopen("magician.in","r",stdin);
	freopen("magician.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)f[i]=i;
	while(m--)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		int fa=findf(a),fb=findf(b);
		if(fa==fb)ans=ans*2%mod;
		else f[fa]=fb;
		printf("%d\n",(ans-1+mod)%mod);
	}
	return 0;
}

B.守卫者的挑战

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define _rep(i,a,b) for(int i=(a);i<=(b);i++)
#define _for(i,a,b) for(int i=(a);i<(b);i++)
int a[201],N,L,K;
double ans,p[201],f[2][201][401];
int main()
{
	freopen("guard.in","r",stdin);
	freopen("guard.out","w",stdout);
	scanf("%d%d%d",&N,&L,&K),K=min(K,N);
	_rep(i,1,N)scanf("%lf",&p[i]),p[i]/=100.000000;
	_rep(i,1,N)scanf("%d",&a[i]);
	f[0][0][K+200]=1.000000;
	_for(i,0,N)
	{
		memset(f[(i+1)&1],0,sizeof(f[(i+1)&1]));
		_rep(j,0,N)_rep(k,-N+200,N+200)
		    if(a[i+1]==-1)
		        f[(i+1)&1][j+1][k-1]+=f[i&1][j][k]*p[i+1],f[(i+1)&1][j][k]+=f[i&1][j][k]*(1.000000-p[i+1]);
		    else
		        f[(i+1)&1][j+1][min(N+200,k+a[i+1])]+=f[i&1][j][k]*p[i+1],f[(i+1)&1][j][k]+=f[i&1][j][k]*(1.000000-p[i+1]);
	}
	_rep(j,L,N)_rep(k,0,N)
	    ans+=f[N&1][j][k+200];
	printf("%.6f\n",ans);
	return 0;
}

C.终极武器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述
在这里插入图片描述

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
#define rg register
#define x first
#define y second
#define MP(a,b) make_pair(a,b)
const int N=1e4+10;
struct node{
	int dat,side;//dat排序前的下标,side=1为左,side=2为右 
	ll low;
	node(){}
	node(ll _a,int _b,int _c):low(_a),dat(_b),side(_c){}
	bool operator <(const node&rhs)const{
	return low<rhs.low;}
}c[N*2];
pair<ll,ll> a[N],b[N];
int n,k,m,link,tot,i,j,f[N*3][10];
bool g[10][10],v[10];//9*9的邻接矩阵 
map<ll,int>hx;//离散化 
inline void change(node a){a.side==1?b[a.dat].x--:b[a.dat].y--;}
//可以发现最初第 k 位上的数字的其中一组是[L/10^k %10 +1, R/10^k %10 +1),当后面的位经
//过 L%10^k 这个数的时候区间左端减一,经过 R%10^k 这个数的时候区间右端减一。
inline void Crash(int v[10])//删去不能互相转化的数之间的边 
{
	for(int i=1;i<=9;i++)
	    for(int j=1;j<=9;j++)
	        if(v[i]&&!v[j]&&g[i][j])g[i][j]=g[j][i]=0,link-=2; 
}
inline void calc()//特殊处理个位情况 
{
	int i,j,l,r;ll now,L,R;
	for(now=-1,i=1;i<=n;i++,now=R)
	{
		l=a[i].x%10,r=a[i].y%10;//个位上是开区间 
		L=a[i].x/10,R=a[i].y/10;
		if(L!=now&&now>0)Crash(f[0]),memset(f[0],0,sizeof(f[0]));//已经不再一个区间里了 
		if(L!=R)//除去个位是不一样的,所以只需分别满足 
		{
			for(j=l;j<=9;j++)f[0][j]++;//从l到9互相转化不会比左区间更小 
			Crash(f[0]);memset(f[0],0,sizeof(f[0]));
			for(j=1;j<r;j++)f[0][j]++;//从1到r互相转化不会比右区间更大 
		}
		else for(j=l;j<r;j++)f[0][j]++;//l到r互相转化同时满足不会变小变大 
	}
	Crash(f[0]);
}
inline bool solve(int k)//当前枚举到第k位 
{
	ll l,r,L,R,pow=1,now;
	int i,j,p,q,num=1;
	memset(f,0,sizeof(f));
	for(m=tot=i=0;i<k;i++)pow*=10;//需要乘的幂
	for(i=1;i<=n;i++)
	{
		L=a[i].x/pow,R=a[i].y/pow;
		if(!L&&!R)continue;
		l=a[i].x%pow,r=a[i].y%pow;
		b[++m]=MP(L+1,R+1);
		c[++tot]=node(l,m,1);c[++tot]=node(r,m,2);
	}
	if(!m)return 0;//所有区间都处理完了
	hx.clear();sort(c+1,c+tot+1);//排序离散化
	for(p=1;p<=tot&&!c[p].low;p++)change(c[p]);//更新两端
	for(i=1,now=-1;i<=m;i++,now=R)
	{
		l=b[i].x%10,r=b[i].y%10;
		L=b[i].x/10,R=b[i].y/10;
		if(L!=now&&now>0)hx[now]=num++;
		if(L!=R)
		{
			for(j=l;j<=9;j++)f[num][j]++;
			hx[L]=num++;
			for(j=1;j<r;j++)f[num][j]++;
		}
		else for(j=l;j<r;j++)f[num][j]++;
	} 
	hx[now]=num++;
	for(i=1;i<num;i++)Crash(f[i]);
	for(;p<=tot;p=q)
	{
		for(q=p;q<=tot&&c[q].low==c[p].low;q++)
		{
			change(c[q]);
			now=c[q].side==1?b[c[q].dat].x:b[c[q].dat].y;
			k=now%10,now/=10;
			if(!hx[now])hx[now]=num++;
			now=hx[now];
			if(c[q].side==1)f[now][k]++;else f[now][k]--;
		}
		for(i=1;i<num;i++)Crash(f[i]);
	}
	return 1;
}
int main()
{
	//freopen("in.txt","r",stdin);
	cin>>n>>k;
	for(i=1;i<=n;i++)
	    cin>>a[i].x>>a[i].y,a[i].y++;
	memset(g,1,sizeof(g));link=72;//9*9的完全图
	calc();
	for(i=1;i<k&&solve(i)&&link;i++);//批量处理剩下k-1位 
	for(i=1;i<=9;i++)
	    if(!v[i])
	    {
	    	cout<<i,v[i]=1;
	    	for(j=1;j<=9;j++)
	    	    if(!v[j]&&g[i][j])cout<<j,v[j]=1;
	    	cout<<endl;
		}
	return 0;
}

比赛总结

这次比赛题比上次要难不少。T1将近一个小时才做出来,T2的滚动数组也写炸,T3就不谈了……
存在的问题:
T1的规律没有找出来,T2状态定义有问题且滚动数组打错,T3完全打不动(毒瘤题不想看)
继续补DP专题吧

猜你喜欢

转载自blog.csdn.net/qq_41958841/article/details/83046591