【CSP-J2024复赛冲刺卷4】【3.西游之取经】

题面




#include<bits/stdc++.h>
using namespace std;
struct node
{
	int tp,x,y; //tp(0,1,2)为3种操作 
}b[10];
int n,m;
int a[4];
int w[10];
bool fl;
int p,k,t;
int vis[10],c[10];
//num:当前有多少人
//sum:当前在的人的能力和
//st:在的集合状态(4个位置,1为在,0为不在) 
//tot:一开始的能力和 
int st,sum,num,tot;
int turn(string s)
{
	if(s[0]=='T') return 0;
	if(s[0]=='K') return 1;
	if(s[0]=='N') return 2;
	if(s[0]=='J') return 3;
}
//暴力搜索出所有行动方案(全排列),再判断每一种方案是否可行 
void dfs(int dep,int tmp) //深度,前面通过了多少关(每个人的能力值加了多少个1) 
{
	if(dep>t) //判断这个方案是否可行 
	{
		int sum1=sum+tmp*num,st1=st,islv=num;
		//能力值和,在的人的集合,被救出来的人数 
		for(int i=1;i<=t;i++) //枚举每一次操作 
		{
			int id=c[i];
			int tp=b[id].tp,x=b[id].x,y=b[id].y;
			if(tp==0) sum1+=x;
			if(tp==1)
			{
				if(sum1>=x)
				{
					sum1+=a[y]+tmp;
					st1|=(1<<y);
					islv++;
				}
			}
			else
				if((st1&x)==x) fl=1;
			if(islv==4) fl=1;
		}
		return;
	}
	for(int i=1;i<=k;i++)
	{
		if(!vis[i])
		{
			c[dep]=i; //枚举下一个位置该填什么 
			vis[i]=1;
			dfs(dep+1,tmp);
			vis[i]=0;
		}
	}
}
bool check(int x)
{
	fl=0;
	dfs(1,x);
	return fl;
}
int mk[105]; //取答案时的标记数组 
int ans[105]; //答案数组
int main()
{
//	freopen("travel.in","r",stdin);
//	freopen("travel.out","w",stdout);
	cin >> n >> m;
	for(int i=0;i<4;i++)
	{
		cin >> a[i];
		tot+=a[i];
	}
	for(int o=1;o<=n;o++)
	{
		num=4;
		st=(1<<4)-1;
		sum=tot;
		cin >> p >> k >> t;
		for(int i=1;i<=p;i++)
		{
			string ss;
			cin >> ss;
			int l=turn(ss);
			num--; //少一个人
			st^=(1<<l); //将这一位清零
			sum-=a[l]; //减去能力值 
		}
		for(int i=1;i<=k;i++)
		{
			char op;
			cin >> op;
			if(op=='G')
			{
				int x;
				cin >> x;
				b[i]=((node){0,x,0});
			}
			else if(op=='S')
			{
				int x; string ss;
				cin >> ss >> x;
				b[i]=((node){1,x,turn(ss)});
			}
			else
			{
				int x; string ss;
				cin >> x;
				int nw=0;
				// nw:当前的人物是否存在 
				for(int i=1;i<=x;i++)
				{
					cin >> ss;
					int l=turn(ss);
					nw|=(1<<l);
				}
				b[i]={2,nw,0};
			}
		}
		// 二分:通过这个需要至少多少初始值 
		int l=0,r=101;
		while(l+1<r)
		{
			int mid=(l+r)/2;
			if(check(mid))
			{
				w[o]=mid;
				r=mid;
			}
			else l=mid;
		}
	}
	for(int o=1;o<=m;o++)
	{
		bool flag=0;
		for(int i=1;i<=n;i++)
		{
			if(!mk[i]&&w[i]<=o)
			{
				flag=1;
				ans[o]=i;
				mk[i]=1;
				break;
			}
		}
		if(!flag)
		{
			cout << -1;
			exit(0);
		}
	}
	for(int i=1;i<=m;i++) cout << ans[i] << " ";
    return 0;
}

WA15,样例输出1 2 3 4,求救 :melting_face:

  1. 二分改一下,让 lr 意义如下:
    l :过 l 关可能可以(未check过)
    r :过 r 关一定可以过
    原来的在过0关就可以过的中会计算错
    像这样
int l=0,r=101;
while(l<r)
{
	int mid=(l+r)/2;
	if(check(mid))
	{
		w[o]=mid;
		r=mid;
	}
	else l=mid+1;
}
if(!mk[i]&&w[i]<=o)

w_i \le o 改成 w_i \lt o
因为 o 为1时,本身是第1关,需要过1关的是不行的

1 个赞
#include<bits/stdc++.h>
using namespace std;
struct node
{
	int tp,x,y; //tp(0,1,2)为3种操作 
}b[10];
int n,m;
int a[4];
int w[10];
bool fl;
int p,k,t;
int vis[10],c[10];
//num:当前有多少人
//sum:当前在的人的能力和
//st:在的集合状态(4个位置,1为在,0为不在) 
//tot:一开始的能力和 
int st,sum,num,tot;
int turn(string s)
{
	if(s[0]=='T') return 0;
	if(s[0]=='K') return 1;
	if(s[0]=='N') return 2;
	if(s[0]=='J') return 3;
}
//暴力搜索出所有行动方案(全排列),再判断每一种方案是否可行 
void dfs(int dep,int tmp) //深度,前面通过了多少关(每个人的能力值加了多少个1) 
{
	if(dep>t) //判断这个方案是否可行 
	{
		int sum1=sum+tmp*num,st1=st,islv=num;
		//能力值和,在的人的集合,被救出来的人数 
		for(int i=1;i<=t;i++) //枚举每一次操作 
		{
			int id=c[i];
			int tp=b[id].tp,x=b[id].x,y=b[id].y;
			if(tp==0) sum1+=x;
			if(tp==1)
			{
				if(sum1>=x)
				{
					sum1+=a[y]+tmp;
					st1|=(1<<y);
					islv++;
				}
			}
			else
				if((st1&x)==x) fl=1;
			if(islv==4) fl=1;
		}
		return;
	}
	for(int i=1;i<=k;i++)
	{
		if(!vis[i])
		{
			c[dep]=i; //枚举下一个位置该填什么 
			vis[i]=1;
			dfs(dep+1,tmp);
			vis[i]=0;
		}
	}
}
bool check(int x)
{
	fl=0;
	dfs(1,x);
	return fl;
}
int mk[105]; //取答案时的标记数组 
int ans[105]; //答案数组
int main()
{
//	freopen("travel.in","r",stdin);
//	freopen("travel.out","w",stdout);
	cin >> n >> m;
	for(int i=0;i<4;i++)
	{
		cin >> a[i];
		tot+=a[i];
	}
	for(int o=1;o<=n;o++)
	{
		num=4;
		st=(1<<4)-1;
		sum=tot;
		cin >> p >> k >> t;
		for(int i=1;i<=p;i++)
		{
			string ss;
			cin >> ss;
			int l=turn(ss);
			num--; //少一个人
			st^=(1<<l); //将这一位清零
			sum-=a[l]; //减去能力值 
		}
		for(int i=1;i<=k;i++)
		{
			char op;
			cin >> op;
			if(op=='G')
			{
				int x;
				cin >> x;
				b[i]=((node){0,x,0});
			}
			else if(op=='S')
			{
				int x; string ss;
				cin >> ss >> x;
				b[i]=((node){1,x,turn(ss)});
			}
			else
			{
				int x; string ss;
				cin >> x;
				int nw=0;
				// nw:当前的人物是否存在 
				for(int i=1;i<=x;i++)
				{
					cin >> ss;
					int l=turn(ss);
					nw|=(1<<l);
				}
				b[i]={2,nw,0};
			}
		}
		// 二分:通过这个需要至少多少初始值 
		int l=0,r=101;
		while(l<r)
		{
			int mid=(l+r)/2;
			if(check(mid))
			{
				w[o]=mid;
				r=mid;
			}
			else l=mid+1;
		}
	}
	for(int o=1;o<=m;o++)
	{
		bool flag=0;
		for(int i=1;i<=n;i++)
		{
			if(!mk[i]&&w[i]<o)
			{
				flag=1;
				ans[o]=i;
				mk[i]=1;
				break;
			}
		}
		if(!flag)
		{
			cout << -1;
			exit(0);
		}
	}
	for(int i=1;i<=m;i++) cout << ans[i] << " ";
    return 0;
}

WA20

dfs里面:

if(tp==1)

这里漏了个else

会变25分

1 个赞

(继续检查中)

1 个赞