首页 > 其他分享 >2023.8.12测试

2023.8.12测试

时间:2023-08-12 16:01:11浏览次数:61  
标签:12 int flag 测试 SegmentTree sb sa 2023.8 define

\[\text{暑假NOIP模拟赛-6} \]

终于没挂分了

T1 打工

有 \(n\) 个工作,做一个工作要消耗一个时间单位,可以获得价值 \(a_i\),截止日期 \(b_i\),求 \(T\) 单位时间内最多获得多少价值

\(1\leq n\leq 10^6\),\(1\leq a_i,b_i\leq T\leq 10^9\)

先按照时间从小到大排序,然后倒序枚举,将两个时间点的所有工作压入堆里,然后从大到小暴力计算即可,时间复杂度 \(O(n\log n)\)

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

const int N=1000010;

int T,n,cnt,b[N];
LL ans;
struct node{int t,val;}a[N];
vector <int> g[N];
priority_queue <int> q;

bool cmp(node x,node y)
{
	if(x.t==y.t)
		return x.val>y.val;
	return x.t<y.t;
}

int main()
{
	scanf("%d%d",&T,&n);
	for(int i=1; i<=n; i++)
		scanf("%d%d",&a[i].t,&a[i].val);
		
	sort(a+1,a+1+n,cmp);
	
	a[0].t=-1;
	for(int i=1; i<=n; i++)
	{
		if(a[i].t==a[i-1].t)
			g[cnt].push_back(i);
		else
			b[++cnt]=a[i].t,g[cnt].push_back(i);
	}
	
	b[0]=0;
	for(int i=cnt; i>=1; i--)
	{
		int len=g[i].size();
		for(int j=0; j<len; j++)
			q.push(a[g[i][j]].val); 
		int len2=q.size();
		int m=min(b[i]-b[i-1],len2);
		while(m--)
		{
			int x=q.top();  q.pop();
			ans+=(LL)x;
		}
	}
	
	printf("%lld",ans);

	return 0;
}

T2 购物

其实就是P2851 [USACO06DEC] The Fewest Coins G

一眼背包,但是发现背包体积 \(V\) 要达到 \(\sum v_ic_i\)????其实不用,因为 \(v_i\leq 200\),所以背包体积上界 \(V\leq 10^5+200\),做一次 \(\rm 01\) 背包和多重背包即可

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

const int N=210,NN=4010,C=20010,M=100210,maxn=100200;

int n,m,c[N],v[N],tot,tot2;
int t[N],w1[NN],v1[NN],w2[N];
int f[M],g[M];

void divide(int cnt,int val)
{
	int x=1;
	while(cnt>=x)
	{
		w1[++tot]=x*val;
		v1[tot]=x;
		cnt-=x;
		x<<=1;
	}
	if(cnt)
		w1[++tot]=cnt*val,v1[tot]=cnt;
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++)
		scanf("%d",&v[i]);
	for(int i=1; i<=n; i++)
	{
		scanf("%d",&c[i]);
		t[v[i]]+=c[i];
	}
	
	for(int i=1; i<=200; i++)
		if(t[i])
			divide(t[i],i),w2[++tot2]=i;
	
	memset(f,0x3f,sizeof(f));
	memset(g,0x3f,sizeof(g));
	
	f[0]=0;
	for(int i=1; i<=tot; i++)
		for(int j=maxn; j>=w1[i]; j--)
			f[j]=min(f[j-w1[i]]+v1[i],f[j]);
			
	g[0]=0;
	for(int i=1; i<=tot2; i++)
		for(int j=w2[i]; j<=maxn; j++)
			g[j]=min(g[j-w2[i]]+1,g[j]);
	
	int ans=1e9;
	for(int i=m; i<=maxn; i++)
		ans=min(ans,f[i]+g[i-m]);
	
	if(ans==1e9)
		printf("-1");
	else
		printf("%d",ans);
	
	return 0;
}

T3 魔法

其实就是 P5522 [yLOI2019] 棠梨煎雪

真的用了魔法,\(O(qn\log m)\) 卡过了,(不开 \(\rm O_2\) \(1.12s\))

一眼线段树,一个字符串包含 \(\{0,1,?\}\),是三进制,我不会转化,于是直接每个线段树节点都存一个字符数组 \(a\) 代表这个区间的字符串,一个二进制数 \(s\) 表示哪些位置是不确定的(不确定为 \(1\),确定为 \(0\)),还有一个标记 \(flag\) 表示这个区间是否合法。每次合并两个子区间都要 \(O(n)\) 暴力合并,时间复杂度 \(O(qn\log m)\)

放一下暴力代码

#include<bits/stdc++.h>
#define lc p*2
#define rc p*2+1
using namespace std;

const int N=35,M=100017;

struct SegmentTree
{
	char a[N];
	int s;
	bool flag;
	#define a(x,i)  t[x].a[i]
	#define s(x)  t[x].s
	#define flag(x)  t[x].flag
}t[4*M];

int n,m,q,ans,pw[N];
char str[M][N];

void prework()
{
	pw[0]=1;
	for(int i=1; i<=n; i++)
		pw[i]=pw[i-1]*2;
}

void cpy(int p,char q[])
{
	for(int i=1; i<=n; i++)
		a(p,i)=q[i];
}

void work(int p)
{
	s(p)=0;
	for(int i=1; i<=n; i++)
		if(a(p,i)=='?')
			s(p)+=(1<<i-1);
}

void pushup(int p)
{
	flag(p)=(flag(lc)&flag(rc));
	if(!flag(p))
		return;
	for(int i=1; i<=n; i++)
	{
		if(a(lc,i)==a(rc,i))
			a(p,i)=a(lc,i);
		else if(a(lc,i)=='?')
			a(p,i)=a(rc,i);
		else if(a(rc,i)=='?')
			a(p,i)=a(lc,i);
		else
			a(p,i)='?',flag(p)=0;
	}
	if(flag(p))
		s(p)=(s(lc)&s(rc));
}

void build(int p,int l,int r)
{
	if(l==r)
	{
		cpy(p,str[l]);
		work(p);
		flag(p)=1;
		return;
	}
	
	int mid=(l+r)>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	pushup(p); 
}

void merge(SegmentTree &x,SegmentTree p,SegmentTree q)
{
	x.flag=(p.flag&q.flag);
	if(!x.flag)
		return;
	for(int i=1; i<=n; i++)
	{
		if(p.a[i]==q.a[i])
			x.a[i]=p.a[i]; 
		else if(p.a[i]=='?')
			x.a[i]=q.a[i];
		else if(q.a[i]=='?')
			x.a[i]=p.a[i];
		else
			x.a[i]='?',x.flag=0;
	}
	if(x.flag)
		x.s=(p.s&q.s);
}

SegmentTree ask(int p,int l,int r,int ql,int qr)
{
	if(ql<=l && qr>=r)
	{
		SegmentTree res=t[p];
		return res; 
	}
	
	SegmentTree lres,rres,res;
	int mid=(l+r)>>1;
	if(ql<=mid)
		lres=ask(lc,l,mid,ql,qr);
	if(qr>mid)
		rres=ask(rc,mid+1,r,ql,qr);
	if(ql<=mid && qr>mid)
		merge(res,lres,rres);
	else if(ql<=mid)
		res=lres;
	else
		res=rres;
	
	return res;
}

void change(int p,int l,int r,int pos,char rep[])
{
	if(l==r)
	{
		cpy(p,rep);
		work(p);
		return;
	}
	
	int mid=(l+r)>>1;
	if(pos<=mid)
		change(lc,l,mid,pos,rep);
	else
		change(rc,mid+1,r,pos,rep);
	pushup(p);
}

int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1; i<=m; i++)
		scanf("%s",str[i]+1);
	
	build(1,1,m);
	
	prework();
	
	while(q--)
	{
		int op,l,r,pos;
		char A[N];
		scanf("%d",&op);
		if(op==0)
		{
			scanf("%d%d",&l,&r);
			SegmentTree tmp=ask(1,1,m,l,r);
			if(!tmp.flag)
				ans^=0;
			else
			{
				int cnt=0;
				for(tmp.s; tmp.s; tmp.s-=(tmp.s&-tmp.s))
					cnt++;
				ans^=pw[cnt];
			}
			
		}
		else
		{
			scanf("%d%s",&pos,A+1);
			change(1,1,m,pos,A);
		}
	}
	
	printf("%d",ans);

	return 0;
}

考虑怎么优化,其实可以先不考虑 \(?\),对于每个节点,存储两个值 \(sa,sb\),分别表示该位是否一定为 \(1/0\),那如果 \(sa\&sb\ne 0\) 显然就不合法,合并两个区间时只需让它 \(sa'|sa'',sb'|sb''\) 即可

#include<bits/stdc++.h>
#define lc p*2
#define rc p*2+1
using namespace std;

const int N=35,M=100017;

struct SegmentTree
{
	int sa,sb;
	bool flag;
	#define sa(x)  t[x].sa
	#define sb(x)  t[x].sb
	#define flag(x)  t[x].flag
}t[4*M];

int n,m,q,ans,pw[N],va[M],vb[M];
char str[N];

void prework()
{
	pw[0]=1;
	for(int i=1; i<=n; i++)
		pw[i]=pw[i-1]*2;
}

void pushup(int p)
{
	flag(p)=(flag(lc)&flag(rc));
	if(!flag(p))
		return;
	sa(p)=(sa(lc)|sa(rc));
	sb(p)=(sb(lc)|sb(rc));
	if(sa(p)&sb(p))
		flag(p)=0;
}

void build(int p,int l,int r)
{
	if(l==r)
	{
		sa(p)=va[l];  sb(p)=vb[l];
		flag(p)=1;
		return;
	}
	
	int mid=(l+r)>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	pushup(p); 
}

void merge(SegmentTree &x,SegmentTree p,SegmentTree q)
{
	x.flag=(p.flag&q.flag);
	if(!x.flag)
		return;
	x.sa=(p.sa|q.sa);
	x.sb=(p.sb|q.sb);
	if(x.sa&x.sb)
		x.flag=0;
}

SegmentTree ask(int p,int l,int r,int ql,int qr)
{
	if(ql<=l && qr>=r)
	{
		SegmentTree res=t[p];
		return res; 
	}
	
	SegmentTree lres,rres,res;
	int mid=(l+r)>>1;
	if(ql<=mid)
		lres=ask(lc,l,mid,ql,qr);
	if(qr>mid)
		rres=ask(rc,mid+1,r,ql,qr);
	if(ql<=mid && qr>mid)
		merge(res,lres,rres);
	else if(ql<=mid)
		res=lres;
	else
		res=rres;
	
	return res;
}

void change(int p,int l,int r,int pos)
{
	if(l==r)
	{
		sa(p)=va[l];  sb(p)=vb[l];
		flag(p)=1;
		return;
	}
	
	int mid=(l+r)>>1;
	if(pos<=mid)
		change(lc,l,mid,pos);
	else
		change(rc,mid+1,r,pos);
	pushup(p);
}

int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1; i<=m; i++)
	{
		scanf("%s",str+1);
		for(int j=1; j<=n; j++)
		{
			if(str[j]=='1')
				va[i]+=(1<<j-1);
			if(str[j]=='0')
				vb[i]+=(1<<j-1);
		}
	}
	
	build(1,1,m);
	
	prework();
	
	while(q--)
	{
		int op,l,r,pos;
		char A[N];
		scanf("%d",&op);
		if(op==0)
		{
			scanf("%d%d",&l,&r);
			SegmentTree tmp=ask(1,1,m,l,r);
			if(!tmp.flag)
				ans^=0;
			else
			{
				int cnt=0,s=(tmp.sa|tmp.sb);
				for(s; s; s-=(s&-s))
					cnt++;
				ans^=pw[n-cnt];
			}
			
		}
		else
		{
			scanf("%d%s",&pos,str+1);
			va[pos]=vb[pos]=0;
			for(int i=1; i<=n; i++)
			{
				if(str[i]=='1')
					va[pos]+=(1<<i-1);
				if(str[i]=='0')
					vb[pos]+=(1<<i-1);
			}
			change(1,1,m,pos);
		}
	}
	
	printf("%d",ans);

	return 0;
}

\(100+100+100+0=300\)

标签:12,int,flag,测试,SegmentTree,sb,sa,2023.8,define
From: https://www.cnblogs.com/xishanmeigao/p/17624938.html

相关文章

  • LGJOI20230812
    LGJ水场。这场总体题比较简单,所以分比较高。A有\(n\)项工作,完成一项工作需要\(1\)单位时间。每项工作有个截止时间\(t\)和报酬\(v\),需要在第\(t\)单位时间前完成工作才能得到\(v\)的报酬。给定\(T\),求\(T\)时间后获得报酬的最大值。solution:简单贪心。将工作......
  • Gitc错误Failed to connect to 127.0.0.1 port 1080 Connection refused拒绝连接错误
    一、git拒绝连接原因分析使用git从远程仓库下载代码出现上述的错误是因为使用了proxy代理,所以要解决该问题,核心操作就是要取消代理二、解决方式1、查看Linux当前有没有使用代理通过git的配置文件查看有无使用代理(没有成功)查询是否使用代理:gitconfig--globalhttp.proxyg......
  • 2023-08-12 记录一则随机密码生成脚本
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=......
  • 【230812-1】指数比较大小:16^18 vs 18^16
    ......
  • 【230812-2】指数比较大小:13^17 vs 17^13
    ......
  • 学习平板如何访问外网(2023.8.12)
    嗨!今天我教大家学习平板如何访问外网(这篇文章就是我用学习平板访问外网写的)首先,你要确保你的平板里安装了快对(原快对作业),然后打开它。在“我的”页面中往下滑找到设置,在设置往下滑中找到“第三方信息共享清单”,点进去,点击第一个腾讯的SDK下面的网站,再点击进去,点击右上角的腾讯云......
  • Typora 激活教程(2023最新图文教程,测试有效)
    下载Typora激活补丁下载地址 https://kdocs.cn/l/chV3CWzeXgdE下载成功后解压,目录如下:typora激活补丁目录,选择第二种方式Typora激活补丁包解压目录安装Typora作者在写这篇教程的时候,Typora最新版本号为1.3.8,通过如下链接下载Typora,下载成功后,直接双击安装即可:......
  • 2023.8.7-2023.8.14暑假第五周博客
    2023.8.7今天人在外,因此博客休息一天图片如下 2023.8.8今天对hive有了进一步的了解首先要明确一个流程当我打开三台虚拟机,用finalshell连接上后首先要使用如下命令1.su-hadoop切换到hadoop用户,大部分操作都必须在hadoop用户中完成,而千万不要再root中,因为root用户一......
  • 2023.8.11
    今天早上起来,还是和往常一样打球,还有几天就离开了,只能假期回来再和兄弟们一起玩了,下午回家有些无聊了,问兄弟们还来不来,他们答应我出来打几个小时,太好了,终于不用在家里待着了,下午打到56点钟就回家了,爸妈还没回来,赶紧把饭蒸好,舒服了,晚上有些累了,躺着突然就睡着了,半夜起来写下这些,明......
  • Linux 发行版 Debian 12.1 发布
    在今年6月初,Debian12“bookworm”发布,而日前Debian迎来了12.1版本,主要修复系统用户创建等多个安全问题。Debian是最古老的GNU/ Linux 发行版之一,也是许多其他基于Linux的操作系统的基础,包括Ubuntu、Kali、MX和树莓派OS等。这个操作系统以稳定性为重,不追......