数论7.13

7.13 数论练习#

P4301 新Nim游戏#

思路

考虑这是 Nim 游戏,想要先手必胜,就要让对方在第一回合无论拿走几堆后剩下的所有堆异或和都不为 0

考虑线性基,若插进去的 x 最后为 0 就说明 x 不能插

所以搞一下贪心,将所有石子堆 ai 按个数从大到小遍历

能插就插,否则就拿走

简单证一下:如果对于 b1b2bk=x 那么根据 b1b2bki=1kbi 可知拿走 x 更优

所以让大的先插进去会更优

// Problem: P4301 [CQOI2013] 新Nim游戏
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4301
// Memory Limit: 125 MB
// Time Limit: 1000 ms

#include<bits/stdc++.h>
using namespace std;

#define int long long

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

const int N=105;

int n;
int a[N],p[N];

signed main(){
	n=read();
	int ans=0;
	for(int i=1;i<=n;++i) a[i]=read();
	sort(a+1,a+n+1);
	for(int i=n;i;--i){
		int x=a[i];
		for(int j=31;j>=0;--j){
			if((1<<j)&x){
				if(p[j]) x^=p[j];
				else{
					p[j]=x;
					break;
				}
			}
		}
		if(!x) ans+=a[i];
	}
	cout<<ans;
}

P4151 最大XOR和路径#

思路

由于是最大异或和,考虑线性基

显然对于 1n 的路径上每一个环都可以选择遍历

分两种情况讨论:

  • 1n 只有一条路径,此时把路径上可遍历的所有的环的异或和扔进线性基,求最大就行
  • 1n 不止一条路径,此时 1n 也在一个环内,这样我们可以随机选一条路径,同时把 1,n 所在的也扔进线性基求最大就行
#include<bits/stdc++.h>
using namespace std;

const int N=5e4+5;

#define ll long long
#define int long long
#define pb push_back

inline ll read(){
	ll x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

struct fake_pair{
	ll a,b;
};

int n,m;
bool vis[N];
ll dis[N],p[N];
vector <fake_pair> G[N];

inline void insert(ll x){
	for(ll i=63;i>=0;--i)
		if(x&(1ll<<i)){
			if(!p[i]){
				p[i]=x;
				return;				
			}
			x^=p[i];
		}
}

inline ll query(ll x){
	for(ll i=63;i>=0;--i)
		if((x^p[i])>x)
			x^=p[i];
	return x;
}

inline void dfs(ll x,ll sum){
	vis[x]=1;
	dis[x]=sum;
	for(auto y:G[x]){
		if(vis[y.a]) insert(sum^y.b^dis[y.a]);
		else dfs(y.a,sum^y.b);
	}
}

signed main(){
	n=read(),m=read();
	for(int i=1;i<=m;++i){
		ll x=read(),y=read(),z=read();
		G[x].pb({y,z});
		G[y].pb({x,z});
	}
	dfs(1,0);
	cout<<query(dis[n]);
}

平面最近(远)点对#

P6247 P1429 加强版

我们充分发扬人类智慧,把所有点按 x,y 从小到大排序

根据数学直觉,取后 50 个点可以求得最近距离

#include<bits/stdc++.h>
using namespace std;

const int N=2e5+5;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int n;

struct pt{
	double x,y;
	inline bool operator < (const pt A) const {
		return x==A.x?y<A.y:x<A.x;
	}
}a[N];

inline double dist(pt A,pt B){
	return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);
}

signed main(){
	n=read();
	double mn=1000000000000000000;
	for(int i=1;i<=n;++i) scanf("%lf %lf",&a[i].x,&a[i].y);
	sort(a+1,a+n+1);
	for(int i=1;i<=n;++i){
		for(int j=i+1;j<=min(i+20,n);++j)
			mn=min(mn,dist(a[i],a[j]));
	}
	printf("%.4lf",sqrt(mn));
}

P7883 加强加强版

上面的方法被卡了

我们充分发扬人类智慧,将 x,y 均加上 2333 并按 x×y 从小到大排序

根据数学直觉,取后 900 个点可以求得最近距离

#include<bits/stdc++.h>
using namespace std;

const int N=4e5+5;
#define re register 
#define int long long
#define nm 2333

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int n;

struct pt{
	int x,y;
	inline bool operator < (const pt A) const {
		return (x+nm)*(y+nm)>(A.x+nm)*(A.y+nm);
	}
}a[N];

inline int dist(pt A,pt B){
	return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);
}

signed main(){
	n=read();
	int mn=1000000000000000;
	for(int i=1;i<=n;++i) a[i].x=read(),a[i].y=read();
	sort(a+1,a+n+1);
	for(re int i=1;i<=n;++i){
		for(re int j=i+1;j<=min(i+900,n);++j)
			mn=min(mn,dist(a[i],a[j]));
	}
	printf("%lld",mn);
}

作者:Into_qwq

出处:https://www.cnblogs.com/into-qwq/p/16473470.html

版权:本作品采用「qwq」许可协议进行许可。

posted @   Into_qwq  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示