NOIP模拟69
T1 石子游戏
大坑未补
T2 大鱼吃小鱼
解题思路
set+桶可以得到 60pts (code)
线段树上二分每一次优先递归右区间从右区间贪心选择,并且记录下更改过的值,在处理完答案之后再复原回去。
处理的时候类似于区间覆盖 laz 标记。
同时用 set 维护一个有序数组用于查看当前值的下一个应该选哪个
code
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
#define ls x<<1
#define rs x<<1|1
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){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 N=8e6+10,INF=1e18;
int n,m,ans,top,now,cnt,sta[N],s[N],lsh[N];
struct Ques{int opt,x,y;}q[N];
struct Node{int dat,bas,laz;}ys[N];
multiset<int> res;
bool can=true,jud=true;
struct Segment_Tree
{
	bool vis[N<<2]; Node tre[N<<2];
	int ceil(int x,int y){return x/y+(x%y!=0);}
	void push_up(int x)
	{
		if(can&&!vis[x]) sta[++top]=x,ys[top]=tre[x],vis[x]=true;
		tre[x].dat=tre[ls].dat+tre[rs].dat;
		tre[x].bas=tre[ls].bas+tre[rs].bas;
	}
	void push_down(int x)
	{
		if(!tre[x].laz) return ;
		if(!vis[ls]) sta[++top]=ls,ys[top]=tre[ls],vis[ls]=true;
		if(!vis[rs]) sta[++top]=rs,ys[top]=tre[rs],vis[rs]=true;
		tre[ls].dat=tre[rs].dat=tre[ls].bas=tre[rs].bas=0; tre[ls].laz=tre[rs].laz=1; tre[x].laz=0;
	}
	void insert(int x,int l,int r,int pos,int val)
	{
		if(l==r) return tre[x].bas+=val,tre[x].dat+=val*lsh[l],void();
		int mid=(l+r)>>1;
		if(pos<=mid) insert(ls,l,mid,pos,val);
		else insert(rs,mid+1,r,pos,val);
		push_up(x);
	}
	int query(int x,int l,int r,int L,int R)
	{
		if(L>R||!tre[x].dat) return 0;
		if(L<=l&&r<=R) return tre[x].dat;
		int mid=(l+r)>>1,sum=0; push_down(x);
		if(L<=mid) sum+=query(ls,l,mid,L,R);
		if(R>mid) sum+=query(rs,mid+1,r,L,R);
		return sum;
	}
	void solve(int x,int l,int r,int L,int R,int &need)
	{
		if(l==r)
		{
			if(tre[x].dat<need) goto V;
			if(!vis[x]) sta[++top]=x,ys[top]=tre[x],vis[x]=true;
			int temp=ceil(need,lsh[l]);
			tre[x].bas-=temp; ans+=temp;
			now+=temp*lsh[l]; need-=temp*lsh[l];
			jud=false; tre[x].dat=tre[x].bas*lsh[l];
			return ;
		} V:;
		if(r<=R&&tre[x].dat<=need)
		{
			need-=tre[x].dat; now+=tre[x].dat;
			if(need<=0) jud=true; ans+=tre[x].bas;
			if(!vis[x]) sta[++top]=x,ys[top]=tre[x],vis[x]=true;
			tre[x].dat=tre[x].bas=0; tre[x].laz=1; return ;
		}
		int mid=(l+r)>>1; push_down(x);
		if(R<=mid) return solve(ls,l,mid,L,R,need),push_up(x),void();
		if(jud) solve(rs,mid+1,r,L,R,need);
		if(jud) solve(ls,l,mid,L,R,need);
		push_up(x);
	}
}T;
void Restore()
{
	for(int i=1;i<=top;i++)
		T.tre[sta[i]]=ys[i],
		T.vis[sta[i]]=false,T.tre[sta[i]].laz=0;
}
void solve(int bas,int goal)
{
	if(bas>=goal) return printf("0\n"),void();
	int temp=goal-bas,rec,need; now=bas; ans=top=0;
	while(temp>0&&now<goal)
	{
		auto it=res.lower_bound(now);
		if(it!=res.end()) rec=*it;
		else  rec=INF;
		need=min(temp,rec-now+1); jud=true;
		int las=need,pos=lower_bound(lsh+1,lsh+cnt+1,now)-lsh-1;
		if(!pos) break;
		T.solve(1,1,cnt,1,pos,need);
		if(need>0||it==res.end()) break;
		temp-=las-need;
	}
	Restore();
	if(need<=0) printf("%lld\n",ans); else printf("-1\n");
}
signed main()
{
	freopen("fish.in","r",stdin); freopen("fish.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++) s[i]=read(),lsh[++cnt]=s[i],res.insert(s[i]);
	m=read();
	for(int i=1;i<=m;i++)
	{
		q[i].opt=read(); q[i].x=read();
		if(q[i].opt==1) q[i].y=read();
		lsh[++cnt]=q[i].x;
	}
	lsh[++cnt]=INF; sort(lsh+1,lsh+cnt+1); cnt=unique(lsh+1,lsh+cnt+1)-lsh-1; can=false;
	for(int i=1;i<=n;i++) T.insert(1,1,cnt,lower_bound(lsh+1,lsh+cnt+1,s[i])-lsh,1);
	can=true;
	for(int i=1;i<=m;i++)
	{
		int opt=q[i].opt,x=q[i].x,y=q[i].y;
		if(opt==1){solve(x,y);continue;}
		if(opt==2)
		{
			can=false; T.insert(1,1,cnt,lower_bound(lsh+1,lsh+cnt+1,x)-lsh,1);
			res.insert(x); can=true; continue;
		}
		can=false; T.insert(1,1,cnt,lower_bound(lsh+1,lsh+cnt+1,x)-lsh,-1);
		res.erase(res.find(x)); can=true;
	}
	return 0;
}
T3 黑客
解题思路
大水题。。
对于 \([1,999]\) 区间内任意两个互质的数,分别求出在 \([a,b],[c,d]\) 两个区间中的上下界。
取一个交集乘上对应的贡献就是答案了。
code
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){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 N=1e3+10,mod=1e9+7;
int a,b,c,d,ans;
vector<pair<int,int> > v;
inline void add(int &x,int y){x+=y;if(x>mod)x-=mod;}
signed main()
{
	freopen("hacker.in","r",stdin); freopen("hacker.out","w",stdout);
	a=read(); b=read(); c=read(); d=read();
	for(int i=1;i<=999;i++)
		for(int j=1;j<=999-i;j++)
			if(__gcd(i,j)==1)
				v.push_back(make_pair(i,j));
	for(int i=0;i<v.size();i++)
	{
		int x=v[i].first,y=v[i].second;
		int lima=ceil((1.0*a)/(1.0*x)),limb=floor((1.0*b)/(1.0*x));
		int limc=ceil((1.0*c)/(1.0*y)),limd=floor((1.0*d)/(1.0*y));
		int l=max(lima,limc),r=min(limb,limd);
		if(l<=r) add(ans,(r-l+1)%mod*(x+y)%mod);
	}
	printf("%lld",ans);
	return 0;
}
T4 黑客(续)
解题思路
丧心病狂考高精。。(改题的时候是我第一次打高精,竟然一遍过??)
数位 DP ,DP 方式有两种:传当前数字的状态或者对于后面数字的限制。
显然第二种 DP 复杂度是优于第一种的,但是第一种直接 __int128 强行压 17 位竟然可以过掉。。
经过本人实测倒数第三个测试点 dfs 函数 方法一调用了大约 25000 次,而方法二竟然只调用了 199次。
可谓天壤之别,剩下的就是板子了。。
code
#include <bits/stdc++.h>
#define ull unsigned long long
#define f() cout<<"Failed"
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){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 N=5e2+10,M=1000;
int n,m,k,can[10];
bool vis[10][10],pas[N][1<<9];
struct Node
{
	int a[M+10];
	void clear(){memset(a,0,sizeof(a));}
	inline Node friend operator << (Node x,int val)
	{
		if(!val) return x;
		int lim=M; while(lim&&!x.a[lim]) lim--;
		for(int i=lim;i>=1;i--) x.a[i+val]=x.a[i];
		for(int i=1;i<=val;i++) x.a[i]=0; return x;
	}
	inline Node friend operator * (Node x,int y)
	{
		int lim=M; while(lim&&!x.a[lim]) lim--;
		Node z; z.clear(); lim+=10;
		for(int i=1;i<=lim;i++) z.a[i]=x.a[i]*y;
		for(int i=1;i<=lim;i++) z.a[i+1]+=z.a[i]/10,z.a[i]%=10;
		return z;
	}
	inline Node friend operator + (Node x,Node y)
	{
		int lim=M; while(lim&&!x.a[lim]&&!y.a[lim]) lim--;
		Node z; z.clear(); lim++;
		for(int i=1;i<=lim;i++) z.a[i]=x.a[i]+y.a[i];
		for(int i=1;i<=lim;i++) z.a[i+1]+=z.a[i]/10,z.a[i]%=10;
		return z;
	}
	void print()
	{
		int lim=M; while(lim>1&&!a[lim]) lim--;
		for(int i=lim;i>=1;i--) printf("%d",a[i]);
		printf("\n");
	}
}f[N][1<<9],g[N][1<<9];
void dfs(int x,int lim)
{
	if(pas[x][lim]) return ; pas[x][lim]=true;
	if(x==n+1) return f[x][lim].a[1]=1,void();
	for(int i=1;i<=k;i++)
	{
		if((lim>>i-1)&1) continue;
		int p1=x+1,p2=lim|can[i]; dfs(p1,p2);
		f[x][lim]=f[x][lim]+f[p1][p2];
		g[x][lim]=g[x][lim]+(f[p1][p2]<<(n-x))*i+g[p1][p2];
	}
	return ;
}
signed main()
{
	freopen("hacker2.in","r",stdin); freopen("hacker2.out","w",stdout);
	n=read(); m=read(); k=read();
	for(int i=1,a,b;i<=m;i++) a=read(),b=read(),can[a]|=1<<(b-1);
	dfs(1,0); f[1][0].print(); g[1][0].print();
	return 0;
}
PS
尽管这一天是我生日,要是没有 星痕Force_A 的提醒还真就忘了。。
NOIP模拟69的更多相关文章
- Noip模拟69 2021.10.5
		考场拼命$yy$高精度结果没学好$for$循环痛失$50pts$,当场枯死 以后一定打对拍,要不考后会... T1 石子游戏 首先要知道典型的$NIM$博弈,就是说如果所有堆石子个数的异或和为$0$则 ... 
- NOIP模拟17.9.22
		NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥ 
- NOIP 模拟4 T2
		本题属于二和一问题 子问题相互对称 考虑对于问题一:知a求b 那么根据b数组定义式 显然能发现问题在于如何求dis(最短路) 有很多算法可供选择 dijsktra,floyed,bfs/dfs,spf ... 
- NOIP模拟赛20161022
		NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ... 
- contesthunter暑假NOIP模拟赛第一场题解
		contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ... 
- NOIP模拟赛 by hzwer
		2015年10月04日NOIP模拟赛 by hzwer (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ... 
- 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程
		数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ... 
- 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1
		题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ... 
- 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1
		题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ... 
随机推荐
- Linux 系统下10个查看网络与监听的命令
			下面列出来的10个基础的每个linux用户都应该知道的网络和监控命令.网络和监控命令类似于这些: hostname, ping, ifconfig, iwconfig, netstat, nslook ... 
- servlet中servletContext的五大作用(三)
			1. 获取web的上下文路径 2. 获取全局的参数 3. 作为域对象使用 4. 请求转发 5. 读取web项目的资源文件 package day10.about_serv ... 
- ES6——静态属性与静态方法
			静态方法只能写在class内,constructor外.通过static关键字声明 静态属性只能写在class外,通过 类名.属性名 = 属性值 声明 //静态属性与静态方法(ES6明确规定,Clas ... 
- promise链式调用的应用
			then在链式调用时,会等前一个then或者函数执行完毕,返回状态,才会执行回调函数. (1)代码顺序执行,第一步调用了函数cook ,cook执行返回了一个promise,promise返回的是成功 ... 
- Three.js 中 相机的常用参数含义
			Three.js 中相机常用的参数有up.position和lookAt. position是指相机所在的位置,将人头比作相机的话,那么position就是人头的中心的位置: up类似于人的脖子可以调 ... 
- Python之win32模块
			如果想在Windows操作系统上使用Python去做一些自动化工作,pywin32模块常常会被用到,它方便了我们调用Windows API. 安装及使用 通过命令pip install pywin32 ... 
- 第17章-x86-64寄存器
			不同的CPU都能够解释的机器语言的体系称为指令集架构(ISA,Instruction Set Architecture),也可以称为指令集(instruction set).Intel将x86系列CP ... 
- CGLib 简析
			背景 JDK 动态代理存在的一些问题: 调用效率低 JDK 通过反射实现动态代理调用,这意味着低下的调用效率: 每次调用 Method.invoke() 都会检查方法的可见性.校验参数是否匹配,过程涉 ... 
- Golang入门学习(三):函数
			文章目录 2.3 函数 2.3.1 基本语法 2.3.2 入门demo: 2.3.3 函数递归: 2.3.4 函数注意事项 2.3.5 init函数 2.3.6 匿名函数 2.3.7 闭包 2.3.8 ... 
- window创建l2tp
			windows上创建一个L2TP的隧道连接 进入控制面板,打开"网络和共享中心",如下图,之后点击"设置新的连接或网络" 进入到"设置连接或网络&qu ... 
