2023.10.5测试

NOIP模拟赛-2023.10.5

T1 魔法少女

定义 f(i)i 所有约数的异或和,求 f(1)f(n) 的异或和

1n1014

容易想到枚举约数然后计算出约数出现的次数并对答案做贡献,复杂度 O(n)

发现约数 x 出现的次数即 nx,这可以用整除分块求出出现次数相同的一段区间 [l,r],复杂度 O(n)

问题是如何快速计算一段区间异或和??

考场思路是,发现两个相邻的偶数和奇数的异或和为 1,所以知道一段区间的头或尾再考虑一下区间长度就可以 O(1) 计算出来

当然你打表就可以发现 1x 的异或和与 xmod4 的结果有关

code
#include<bits/stdc++.h>
#pragma GCC optimize(3,"Ofast","inline")
#define LL long long 
using namespace std;

LL n,ans;

int main()
{
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	
	scanf("%lld",&n);
	
	for(LL l=1,r; l<=n; l=r+1)
	{
		r=n/(n/l);
		LL tmp=n/l,cnt=r-l+1;
		if(tmp%2==0)
			continue;
		if((l&1) && (r&1))
			ans^=l,cnt--;
		else if((l&1) && (r%2==0))	
			ans^=l^r,cnt-=2;
		else if((l%2==0) && (r%2==0))
			 ans^=r,cnt--;
		ans^=((cnt/2)%2); 
	} 
	
	printf("%lld",ans);

	return 0;
}

T2 亿只只因的回家路

UOJ #747.【UNR #6】面基之路

出题人???

注意到一个关键的性质,题意等价于让所有人同时到同一个点的最短时间,没看出来的话很难做

那这样我们就可以枚举他们的汇合点或者汇合边。在点上汇合比较容易,考虑在边上汇合的情况。只要枚举每个人是从边的左侧还是右侧进入即可,复杂度可以做到 O(kmlogn+kn2k+m2k),可以获得 85

其实处理点的情况可以做到 O(kmlogn+kn),但为了处理边的情况多了一个 2k,所以瓶颈在于处理边的情况

我们一开始是枚举每个人从哪侧进入,但最后只考虑进入边时间最晚的人,所以一定存在一种方案,将人进入左侧的时间从小到大排序后,一个前缀从左侧进入,剩余的后缀从右侧进入,时间复杂度 O(kmlogn+kn+mklogk),可以通过

(在 GJOJ 被卡了……)

code
#include<bits/stdc++.h>
#pragma GCC optimize(3,"Ofast","inline")
#define LL long long
#define pli pair<LL,int>
using namespace std;

const int N=1e5+10,M=2e5+10,K=20+10;
const LL INF=1e18;

int n,m,k,a[N];
LL d[N],ans1[N][K],ans2[M],ans=INF;
struct node{int y,z;};vector <node> g[N];
struct E{int x,y,z;}e[M];
bool v[N];

void dijkstra(int s)
{
	priority_queue <pli> q;
	memset(v,0,sizeof(v));
	memset(d,0x3f,sizeof(d));
	d[s]=0;  q.push({0,s});
	while(q.size())
	{
		int x=q.top().second;  q.pop();
		if(v[x])
			continue;
		v[x]=1;
		for(auto v:g[x])
		{
			if(d[v.y]>d[x]+(LL)v.z)
			{
				d[v.y]=d[x]+(LL)v.z;
				q.push({-d[v.y],v.y});
			}
		} 
	}
}

LL calc(LL a,LL b,LL z)
{
	if(min(a,b)+z<=max(a,b))
		return max(a,b);
	z-=max(a,b)-min(a,b);
	return max(a,b)+z/2; 
}

int main()
{
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
    
	memset(ans2,0x3f,sizeof(ans2));
	
	scanf("%d%d",&n,&m,&k);
	for(int i=1; i<=m; i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		z*=2;
		e[i]={x,y,z};
		g[x].push_back({y,z});
		g[y].push_back({x,z});
	}
	scanf("%d",&k);
	a[1]=1;  k++;
	for(int i=2; i<=k; i++)
		scanf("%d",&a[i]);
	
	int S=(1<<k)-1;
	for(int i=1; i<=k; i++)
	{
		dijkstra(a[i]);
		
		for(int j=1; j<=n; j++)
			ans1[j][i]=d[j],ans1[j][0]=max(ans1[j][0],d[j]);
	}

	for(int i=1; i<=n; i++)
		ans=min(ans,ans1[i][0]);
	for(int i=1; i<=m; i++)
	{
		priority_queue <pli> q1,q2;
		for(int j=1; j<=k; j++)
			q1.push({ans1[e[i].x][j],j});
		while(q1.size())
		{
			int x=q1.top().second;  q1.pop();
			q2.push({ans1[e[i].y][x],x});
			ans2[i]=min(ans2[i],calc(q1.top().first,q2.top().first,e[i].z));
		}
		ans=min(ans,ans2[i]);
	}
	
	printf("%lld",ans);
	
	return 0;
}

T3 西琳的魔法字符串

CCPC Finals 2021 I. Reverse LIS

一道题炸出很多前置题

这个题有一个弱化版 CF933A A Twisty Movement。但那题用 dp 可以通过

这里我们转化一下题意,我们枚举 01 的断点 i,那最后的不下降子序列就是 i 前面的 0 的个数加上 i 后面的 1 的个数。如果我们将 0 的权值赋成 11 的权值赋成 1,设权值数组为 a,那么子序列的长度就是 count(S,1)+a[1:i]。所以我们就需最大化 a[1:i]

回到原问题,它支持 k 次区间翻转的操作,最后最大化一个前缀和。其实可以转化为在原串中选出 k+1 个不相交的区间,其中一段为前缀,使得子段和最大

这个可以参考 [DS/贪心记录] CF280D k-Maximum Subsequence Sum 的实现

code
#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int N=2e5+10;
const LL INF=1e18;

int n,q,a[N];
LL last,ans[N];
queue < pair<int,int> > qq;
struct Ask{int k,id;}Q[N];

struct node{int l,r;LL s;};  node zinf={0,0,INF},finf={0,0,-INF};
node operator + (const node &a,const node &b){return {a.l,b.r,a.s+b.s};}
bool operator < (const node &a,const node &b){return a.s<b.s;}

#define lc(p) p<<1
#define rc(p) p<<1|1
struct Seg
{
	node mx,mn,lmx,rmx,lmn,rmn,sum;
	int rev;  
	#define rev(x) tree[x].rev 
	
	void write(int l,int r,LL s)
	{
		mx=mn=lmx=rmx=lmn=rmn=sum={l,r,s};
		rev=0;
	}
	
	void reverse()
	{
		swap(mx,mn);  swap(lmx,lmn);  swap(rmx,rmn);
		mx.s*=-1;  mn.s*=-1;
		lmx.s*=-1;  rmx.s*=-1;
		lmn.s*=-1;  rmn.s*=-1;
		sum.s*=-1;  rev^=1;
	}
}tree[N<<2];
Seg I={finf,zinf,finf,finf,zinf,zinf,{0,0,0},0};

Seg pushup(Seg p,Seg q)
{
	Seg val=I;
	if(p.mx.s>=1e16)
		return q;
	if(q.mx.s>=1e16)
		return p;
	val.mx=max(max(p.mx,q.mx),p.rmx+q.lmx);
	val.mn=min(min(p.mn,q.mn),p.rmn+q.lmn);
	val.lmx=max(p.lmx,p.sum+q.lmx);
	val.rmx=max(q.rmx,p.rmx+q.sum);
	val.lmn=min(p.lmn,p.sum+q.lmn);
	val.rmn=min(q.rmn,p.rmn+q.sum);
	val.sum=p.sum+q.sum;
	return val;
}

void spread(int p)
{
	if(rev(p))
	{
		tree[lc(p)].reverse();
		tree[rc(p)].reverse();
		rev(p)=0; 
	}
}

void build(int p,int l,int r)
{
	if(l==r)
	{
		tree[p].write(l,r,a[l]);
		return;
	}
	int mid=(l+r)>>1;
	build(lc(p),l,mid);
	build(rc(p),mid+1,r);
	tree[p]=pushup(tree[lc(p)],tree[rc(p)]); 
}

void change(int p,int l,int r,int x,int v)
{
	if(l==r)
	{
		tree[p].write(l,r,v);
		return;
	}
	spread(p);
	int mid=(l+r)>>1;
	if(x<=mid)
		change(lc(p),l,mid,x,v);
	else
		change(rc(p),mid+1,r,x,v);
	tree[p]=pushup(tree[lc(p)],tree[rc(p)]);
}

void reverse(int p,int l,int r,int ql,int qr)
{
	if(ql<=l && qr>=r)
		return tree[p].reverse(),void();
	spread(p);
	int mid=(l+r)>>1;
	if(ql<=mid)
		reverse(lc(p),l,mid,ql,qr);
	if(qr>mid) 
		reverse(rc(p),mid+1,r,ql,qr);
	tree[p]=pushup(tree[lc(p)],tree[rc(p)]); 
}

int main()
{
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    
	scanf("%d",&n);
	for(int i=1; i<=n; i++)
	{
		int c,p;
		scanf("%d%d",&c,&p);
		a[i]=(c==0? 1:-1)*p;
		if(c==1)
			last+=(LL)p;
	}
	
	build(1,1,n);
	
	Seg tur=tree[1];
	if(tur.lmx.s>0)
	{
		last+=tur.lmx.s;
		reverse(1,1,n,tur.lmx.l,tur.lmx.r);
	}
	
	scanf("%d",&q);
	for(int i=1; i<=q; i++)
		scanf("%d",&Q[i].k),Q[i].id=i;
	
	sort(Q+1,Q+1+q,[](Ask a,Ask b){return a.k<b.k;});
	
	int cnt=0;
	for(int i=1; i<=q; i++)
	{
		while(cnt<Q[i].k)
		{
			Seg cur=tree[1];
			if(cur.mx.s<=0)
				break;
			last+=cur.mx.s; 
			reverse(1,1,n,cur.mx.l,cur.mx.r);
			qq.push({cur.mx.l,cur.mx.r});
			cnt++;
		}
		ans[Q[i].id]=last;
	}
	
	for(int i=1; i<=q; i++)
		printf("%lld\n",ans[i]);
	
	return 0;
}

/*
1
1 1
1
0
*/ 

100+80+0+0=180rk16

posted @   xishanmeigao  阅读(20)  评论(0编辑  收藏  举报
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示