ICPC2024 邀请赛西安站 F L题解

F - XOR Game

题意

给定n,k ,k代表0的个数,现在有一个数x初始为0

接下来n个数,每一个数a_i \left ( 0\leq i< n \right )代表2^i这个数字的个数

每次操作可以选择a数组中的一个数字并且可以选择是否将这个x异或上这个数字,然后把这个数字从a数组中删除,Alice先手,Alice想让答案尽可能大,Bob想让答案尽可能小,问最后答案(用n位二进制数输出)

思路

手玩一下可以发现,假设此时某一位数字有a_i个,当a_i>=3的时候,无论谁选择这个数,无论x是否异或上这个数字,对答案都没有任何影响,只有当a_i==2的时候,当其中一个人选择这个数字的时候,另一个人都可以选择对应的操作使得这一位上的答案最小/最大,当a_i==1的时候,ALICE和BOB肯定能选择选,ALICE一定会把x异或上这个数,BOB一定会把这个数直接删掉

于是就把a_i==1的存下来,从大到小遍历,答案一定异或上奇数位的a_i(Alice优先操作),然后把每次操作存下来

然后把0和所有a_i>=3的部分也存下来,判断存下来的操作数是奇数还是偶数,是奇数的话,接下来Bob操作,Bob每一次操作Alice都能找到对应的操作使得这一位为1,是偶数的话Alice的每一次操作Bob都能找到对应的操作使这一位为0

代码

#include <map>
#include <set>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define u1 (u<<1)
#define u2 (u<<1|1)
#define pb push_back
#define pp pop_back()
#define int long long
#define laile cout<<"laile"<<endl
#define lowbit(x) ((x)&(-x))
#define double long double
#define sf(x) scanf("%lld",&x)
#define sff(x,y) scanf("%lld %lld",&x,&y)
#define sd(x) scanf("%Lf",&x)
#define sdd(x,y) scanf("%Lf %Lf",&x,&y)
#define _for(i,n) for(int i=0;i<(n);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
#define _pre(i,a,b) for(int i=(a);i>=(b);--i)
#define all(x) (x).begin(), (x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef unsigned long long ULL;
typedef pair<int,int>PII;
const int N=1e6+10,INF=4e18;
int n,m;
string s,pres;
vector<int>v;
void solve()
{
	cin>>n>>m;
	_rep(i,0,n-1)s+='0',pres+='0';
	_rep(i,0,n-1)
	{
		int x;
		cin>>x;
		if(!x)continue;
		if(x==1)v.pb(i);
		else 
		{
			if(x>2)m+=x-2;
			pres[i]='1';
		}
	}
	int res=0;
	reverse(all(v));
	_for(i,(int)v.size())
	{
		if(i%2==0)s[v[i]]='1';
		m++;
	}
	if(m&1)
	{
		_rep(i,0,n-1)
			if(s[i]=='0')s[i]=pres[i];
	}
	_pre(i,n-1,0)
		cout<<s[i];
	return ;
}
signed main()
{
	IOS;
	int T=1;
//	cin>>T
	while(T--)
		solve();
	return 0;
}

L - Rubbish Sorting

思路

操作为1的时候,用一遍深搜把所有情况的编号用map存下来(注意不匹配被标记为‘*’),时间复杂度最多为2^5=32比如

假设输入样例

3
1 aa 2
1 ab 1
2 ba

输入1 aa 2

那么此时mp[aa]=2,mp[a]=2,mp[*]=2,mp[a*]=2,mp[*a]=2,mp[**]=2

假设在这之后输入1 ab 1

那么接下来mp[ab]=1,mp[a]=1(更新),mp[a*]=1(更新),mp[*b]=1,mp[**]=1(更新)

接下来询问,只需要深搜找到匹配字母数量最多的对应的map编号即可(不匹配被标记为‘*’)

假设输入 2 ba

此时mp[]找不到"ba",于是深搜一个不匹配mp[b*]和mp[*a],找到了并且输出这一轮的最小序号也就是mp[*a]=2,于是这一次询问终止,不需要在深搜两个不匹配的情况,此时输出序号2

代码

#include<bits/stdc++.h>
using namespace std;
#define sf(x) scanf("%lld",&x)
#define sff(x,y) scanf("%lld%lld",&x,&y)
#define endl '\n'
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define pf(x) printf("%lld",x)
#define pii pair<int,int> 
#define f first 
#define s second
#define int long long

typedef unsigned long long ull;

//
//
const int N = 3e5+10;
const ull P = 13331;
unordered_map<ull,int> mp;
int m;
char ss[N];
void mpp(ull str,int n)
{
	if(mp.count(str))
		mp[str]=min(mp[str],n);
	else mp[str]=n;
}

void dfs1(int u,ull now,int op)
{
	ull z = now;
	if(u==strlen(ss))
	{
		int n=5-strlen(ss);
		while(n--) now=now*P+(ull)'*';
		mpp(now,op);
		return ;
	}	
	dfs1(u+1,now*P+ss[u],op);
	dfs1(u+1,now*P+'*',op);
}

int dfs2(int u,ull now,int j,int now1)
{
	int res=0x3f3f3f3f;
	if(u==strlen(ss))
	{
		int n=5-strlen(ss);
		while(n--) now=now*P+(ull)'*';
		if(mp.count(now)) return mp[now];
		else return 0x3f3f3f3f;
	}
	if(now1<j){	
		res=min(res,dfs2(u+1,now*P+'*',j,now1+1));
	}
	
	res=min(res,dfs2(u+1,now*P+ss[u],j,now1));	
	return res;
}
void solve()
{
	sf(m);
	for(int i=1;i<=m;i++)
	{
		int op,x;
		sf(op);
		scanf("%s",ss);
		if(op==1){
			sf(x);
			dfs1(0,0,x);
		}
		else
		{
			int len=strlen(ss);
			for(int j=0;j<=len;j++)
			{
				int now=dfs2(0,0,j,0);
				if(now!=0x3f3f3f3f) 
				{
					pf(now);
					puts("");
					break;
				}
			}
		}
	}
}
signed main()
{
//	IOS
	int _=1;
	while(_--)
		solve();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值