多校冲刺 NOIP 20211113 模拟 (29)

T4原题忘记如何统计答案,被迫暴力。。。。

T1 子集和

签到题,直接背包就行了

Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int maxn=1e5+5;
int n,b[maxn],m,a[maxn],top;
int bb[maxn],sum;
signed main()
{
	freopen("subset.in","r",stdin);
	freopen("subset.out","w",stdout);
	n=read();m=read();
	for(int i=0;i<=m;i++) b[i]=read();
	int tmp=1; bb[0]=1;
	while(tmp<=m)
	{
		while(!b[tmp]) tmp++;
		int num=b[tmp]-bb[tmp];
		if(num)
		{
			int x=tmp;
			for(int i=1;i<=num;i++)
			{
				a[++top]=tmp;
				for(int v=m;v>=tmp;v--)
				bb[v]+=bb[v-tmp];
			}
		}
		tmp++;	
	}
	for(int i=1;i<=top;i++) printf("%lld ",a[i]);
}

T2 异或

有许多不同的做法,这里给出我考场上的做法,

我们首先对所有点建出一棵 \(Trie\) 树,再将每个点依次删掉顺便统计答案,

答案肯定是被删的与没有被删的点组合出的答案,那么再维护这个点被删掉的与没有被删掉的个数

以及这一层所有左子树删掉的与右子树没被删掉的乘积和,右子树删掉与左子树没被删掉的乘积和

然后统计答案就好了

Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int maxn=5e5+5;
int a[maxn],n;
namespace sub{
	ll ans=0;
	struct Trie{
		int tr[maxn*30][2],root,cnt,ws[maxn*30],ys[maxn*30];ll cj[40][2];
		inline void init(){cnt=1;root=1;}
		inline void insert(int x)
		{
			int u=root;
			for(int i=30;i>=0;i--)
			{
				int val=(x&(1<<i))?1:0;
				if(x&(1<<i)) val=1;
				else val=0;
				ws[u]++;
				if(!tr[u][val]) tr[u][val]=++cnt;
				u=tr[u][val];
			}
			ws[u]++;
		}
		inline void getans(int x)
		{
			int u=root;
			for(int i=30;i>=0;i--)
			{
				int val=(x&(1<<i))?1:0;
				if(x&(1<<i)) val=1;
				else val=0;
				ws[u]--;ys[u]++;
				if(val) ans+=cj[i][0]; else ans+=cj[i][1];
				if(val)
				{
					cj[i][1]-=1ll*ws[tr[u][1]]*ys[tr[u][0]];
					cj[i][1]+=1ll*(ws[tr[u][1]]-1)*ys[tr[u][0]];
					cj[i][0]-=1ll*ws[tr[u][0]]*ys[tr[u][1]];
					cj[i][0]+=1ll*ws[tr[u][0]]*(ys[tr[u][1]]+1);
				}
				else
				{
					cj[i][1]-=1ll*ws[tr[u][1]]*ys[tr[u][0]];
					cj[i][1]+=1ll*ws[tr[u][1]]*(ys[tr[u][0]]+1);
					cj[i][0]-=1ll*ws[tr[u][0]]*ys[tr[u][1]];
					cj[i][0]+=1ll*(ws[tr[u][0]]-1)*ys[tr[u][1]];
				}
				u=tr[u][val];
			}
			ws[u]--;ys[u]++;
		}
	}T;
	inline void main()
	{
		T.init();
		for(int i=1;i<=n;i++) T.insert(a[i]);
		for(int i=1;i<=n;i++) T.getans(a[i]);
		printf("%lld\n",ans);
	}
}
signed main()
{
	freopen("xor.in","r",stdin);
	freopen("xor.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	sub::main();return 0;
}

T3 异或 2

知道个柿子就能70了,剩下就是写高精,真jb烦

Code
#include<bits/stdc++.h>
#define LL __int128
#define ULL __uint128_t
#define int long long
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int base=10000000000000000ll;
struct gj{
	int l,c[101]; ULL has; gj(){}
	gj(int x){memset(c,0,sizeof(c));l=1;c[1]=x;}
	inline void geths(){has=l; for(int i=1;i<=l;i++) has*=c[i];}
	inline void print(){printf("%lld",c[l]);for(int i=l-1;i>0;i--)printf("%016lld",c[i]);puts("");}
	inline gj operator+(const gj &a)const
	{
		gj res=gj(0); res.l=max(l,a.l); for(int i=1;i<=res.l;i++)
		{res.c[i]+=c[i]+a.c[i];res.c[i+1]+=res.c[i]/base;res.c[i]%=base;}
		if(res.c[res.l+1]) ++res.l; res.geths(); return res;
	}
	inline gj operator-(const int &a)const
	{
		gj res=gj(0);res.l=l;for(int i=1;i<=l;i++)res.c[i]=c[i];
		int pos=1;res.c[1]-=a;
		while(res.c[pos]<0){res.c[pos]+=base;++pos;--res.c[pos];}
		if(!res.c[res.l])--res.l;res.geths();return res;
	}
	inline gj operator*(const int &a)const
	{
		gj res=gj(0); res.l=l;for(int i=1;i<=res.l;i++)
		{res.c[i]+=c[i]*a;res.c[i+1]+=res.c[i]/base;res.c[i]%=base;}
		if(res.c[res.l+1])++res.l;res.geths();return res;
	}
	inline gj operator/(const int &a)const
	{
		gj res=gj(0);res.l=l;for(int i=1;i<=l;i++)res.c[i]=c[i];
		if(res.c[1]&1)--res.c[1];
		for(int i=l;i;i--){if(res.c[i]&1) res.c[i-1]+=base;res.c[i]/=a;}
		if(!res.c[l]) --res.l; res.geths(); return res;
	}
}n;
map<ULL,gj>mp; 
inline gj Read()
{
	char ch[1000];
	gj res=gj(0); scanf("%s",ch+1); int len=strlen(ch+1);
	for(int i=1;i<=len;i++) res=res*10+gj(ch[i]-'0');
	return res;
}
inline gj dfs(gj now)
{
	if(now.l<=1&&now.c[1]<=0) return mp[now.has]=gj(0);
	if(mp.find(now.has)!=mp.end()) return mp[now.has];
	gj k=now/2;if(now.c[1]&1) mp[now.has]=dfs(k)*4+k*6;
	else mp[now.has]=dfs(k)*2+dfs(k-1)*2+k*4-4;
	return mp[now.has];
}
signed main()
{
	freopen("rox.in","r",stdin);
	freopen("rox.out","w",stdout);
	gj n=Read();dfs(n).print();
}

T4 卡牌游戏

原题,基环树+换根dp,对于每个联通块求出最小结果及其方案,乘一块就行了

Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int maxn=2e5+5,mod=998244353;
int head[maxn],f[3][maxn],num=1,n,m;
struct edge{int to,nxt,v;}e[maxn<<1];
inline void add(int x,int y,int val)
{e[++num]=(edge){y,head[x],val};head[x]=num;}
namespace solve1{
	int dian,bian;bool vis[maxn];
	inline void dfs(int x,int fa)
	{
		dian++;vis[x]=1;for(int i=head[x];i;i=e[i].nxt)
		{bian++;int y=e[i].to;if(y!=fa&&!vis[y])dfs(y,x);}
	}
	inline bool pd()
	{	
		memset(vis,0,sizeof(vis));for(int i=1;i<=n*2;i++)
		if(!vis[i]){dian=bian=0;dfs(i,0);if(dian*2<bian)return false;}
		return true;
	}
}
namespace solve2{
	bool v[maxn];vector<int>tmp;
	int st,en,ned;
	inline void dfs1(int x,int fa)
	{
		v[x]=1;f[1][x]=0;for(int i=head[x];i;i=e[i].nxt)
		if(e[i].to!=fa){int y=e[i].to;
		if(!v[y]){dfs1(y,x);f[1][x]+=f[1][y]+e[i].v;}
		else st=x,en=y,ned=i;}
	}
	inline void dfs2(int x,int fa)
	{
		tmp.push_back(f[2][x]);
		for(int i=head[x];i;i=e[i].nxt)
		if(e[i].to!=fa&&i!=ned&&i!=(ned^1))
		{
			int y=e[i].to;
			if(e[i].v) f[2][y]=f[2][x]-1;
			else f[2][y]=f[2][x]+1;
			dfs2(y,x);
		}
	}
	signed ppp()
	{
		int minn=0,ans=0,ans2=1;
		for(int i=1;i<=2*n;i++)
		if(!v[i])
		{
			st=en=ned=-1;tmp.clear();minn=0;
			dfs1(i,0);f[2][i]=f[1][i];dfs2(i,0);
			if(st==-1)
			{	
				sort(tmp.begin(),tmp.end());
				for(int i=0;i<tmp.size();i++)
				if(tmp[i]==tmp[0])minn++;else break;
				ans+=tmp[0];
			}
			else
			{
				ned%=2;
				if(f[2][st]+ned==f[2][en]+(ned^1)) minn=2;
				else minn=1;
				ans+=min(f[2][st]+ned,f[2][en]+(ned^1));
			}
			ans2=(ans2*minn)%mod;
		}
		printf("%lld %lld\n",ans,ans2);
		return 0;
	}
}
signed main()
{
	freopen("card.in","r",stdin);
	freopen("card.out","w",stdout);
	n=read();num=1;
	for(int i=1;i<=n;i++)
	{
		int x=read(),y=read();
		add(x,y,1);
		add(y,x,0);
	}
	if(!solve1::pd()){puts("-1 -1");return 0;}
	solve2::ppp();
}
posted on 2021-11-13 21:20  JYFHYX  阅读(24)  评论(0编辑  收藏  举报