NOIP2012题解
NOIP2012题解
Day1
Vigenère 密码 vigenere
直接模拟就好了,对于那张表找找规律就很短了。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 1010
char k[MAX],c[MAX];
char get(char a,char b){return (((b-97)-(a-97)+26)%26)+97;}
int main()
{
	scanf("%s",k);scanf("%s",c);
	for(int i=0,l=strlen(c),lk=strlen(k);i<l;++i)
	{
		int x=0;
		if(c[i]>='A'&&c[i]<='Z')c[i]+=32,x=-32;
		if(k[i%lk]>='A'&&k[i%lk]<='Z')k[i%lk]+=32;
		putchar(get(k[i%lk],c[i])+x);
	}
	puts("");return 0;
}
国王游戏 game
考虑两个人的先后顺序对于答案的影响。分类讨论之后不难发现每个人按照左手乘右手的值从小往大排序显然最优。高精度计算答案即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 1050
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n;
struct peo{int l,r;}p[MAX];
bool operator<(peo a,peo b){return 1ll*a.l*a.r<1ll*b.l*b.r;}
struct Bigint
{
	int s[5000],ws;
	void init(){s[ws=1]=1;}
	void Multi(int b)
		{
			for(int i=1;i<=ws;++i)s[i]*=b;
			for(int i=1;i<=ws;++i)s[i+1]+=s[i]/10,s[i]%=10;
			while(s[ws+1])++ws,s[ws+1]+=s[ws]/10,s[ws]%=10;
		}
	void output(){for(int i=ws;i;--i)printf("%d",s[i]);puts("");}
}ans,now;
bool operator<(Bigint a,Bigint b)
{
	if(a.ws!=b.ws)return a.ws<b.ws;
	for(int i=a.ws;i;--i)
		if(a.s[i]!=b.s[i])return a.s[i]<b.s[i];
	return false;
}
Bigint operator/(Bigint a,int b)
{
	int r=0;
	for(int i=a.ws;i;--i)
	{
		r=r*10+a.s[i];
		a.s[i]=r/b;r%=b;
	}
	while(a.ws>1&&!a.s[a.ws])--a.ws;
	return a;
}
int main()
{
	n=read();now.init();now.Multi(read());read();
	for(int i=1;i<=n;++i)p[i].l=read(),p[i].r=read();
	sort(&p[1],&p[n+1]);
	for(int i=1;i<=n;++i)
	{
		ans=max(ans,now/p[i].r);
		now.Multi(p[i].l);
	}
	ans.output();
	return 0;
}
开车旅行 drive
好题。
预处理出在每个位置\(A\)和\(B\)分别会走到哪里,可以用链表实现。接下来把\(A,B\)分别走一次看做一组,直接倍增求解即可。注意最后\(A\)还可能可以单独走一次。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 100100
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n;
int h[MAX];
int dA[MAX],dB[MAX];
namespace Destination
{
	int nt[MAX],lt[MAX],p[MAX],id[MAX];
	bool cmp(int a,int b){return h[a]<h[b];}
	void upd(int &mx,int &mxx,int i,int j)
	{
		int s=abs(h[i]-h[j]);if(!j)return;
		if(!mx||s<abs(h[i]-h[mx])||(s==abs(h[i]-h[mx])&&h[j]<h[mx]))swap(mx,mxx),mx=j;
		else if(!mxx||s<abs(h[i]-h[mxx])||(s==abs(h[i]-h[mxx])&&h[j]<h[mxx]))mxx=j;
	}
	void Work()
	{
		for(int i=1;i<=n;++i)p[i]=i;
		sort(&p[1],&p[n+1],cmp);
		for(int i=1;i<=n;++i)lt[p[i]]=p[i-1],nt[p[i]]=p[i+1];
		for(int i=1;i<=n;++i)
		{
			int mx=0,mxx=0;
			upd(mx,mxx,i,lt[i]);upd(mx,mxx,i,lt[lt[i]]);
			upd(mx,mxx,i,nt[i]);upd(mx,mxx,i,nt[nt[i]]);
			nt[lt[i]]=nt[i];lt[nt[i]]=lt[i];lt[0]=nt[0]=0;
			dA[i]=mxx;dB[i]=mx;
		}
	}
}
int p[17][MAX],sA[17][MAX],sB[17][MAX];
void Query(int S,int X,int &disA,int &disB)
{
	disA=disB=0;
	for(int i=16;~i;--i)
		if(p[i][S]&&X>=sA[i][S]+sB[i][S])
			disA+=sA[i][S],disB+=sB[i][S],X-=sA[i][S]+sB[i][S],S=p[i][S];
	if(dA[S]&&X>=abs(h[S]-h[dA[S]]))
		disA+=abs(h[S]-h[dA[S]]);
}
int main()
{
	n=read();
	for(int i=1;i<=n;++i)h[i]=read();
	Destination::Work();
	for(int i=1;i<=n;++i)
	{
		p[0][i]=dB[dA[i]];
		sA[0][i]=abs(h[i]-h[dA[i]]);
		sB[0][i]=abs(h[dA[i]]-h[dB[dA[i]]]);
	}
	for(int i=1;i<17;++i)
		for(int j=1;j<=n;++j)
		{
			p[i][j]=p[i-1][p[i-1][j]];
			sA[i][j]=sA[i-1][j]+sA[i-1][p[i-1][j]];
			sB[i][j]=sB[i-1][j]+sB[i-1][p[i-1][j]];
		}
	int X=read();double Rate=1e18;int pos=0;
	for(int i=1;i<=n;++i)
	{
		int disA,disB;double V=0;
		Query(i,X,disA,disB);
		if(!disB)V=1e18-1;
		else V=1.0*disA/disB;
		if(V<Rate)Rate=V,pos=i;
		else if(V==Rate&&h[i]>h[pos])pos=i;
	}
	printf("%d\n",pos);
	int Q=read();
	while(Q--)
	{
		int S=read(),X=read(),disA,disB;
		Query(S,X,disA,disB);
		printf("%d %d\n",disA,disB);
	}
	return 0;
}
Day2
同余方程 mod
\(exgcd\)模板题
#include<iostream>
using namespace std;
int a,b;
void exgcd(int a,int b,int &x,int &y){if(a==0){x=0;y=1;return;}exgcd(b%a,a,y,x);x-=b/a*y;}
int inv(int a,int b){int x,y;exgcd(a,b,x,y);x=(x%b+b)%b;return x;}
int main()
{
	cin>>a>>b;
	cout<<inv(a,b)<<endl;
	return 0;
}
借教室 classroom
二分答案,差分\(check\)。
#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 1000100
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n,m,s[MAX],d[MAX],l[MAX],r[MAX],a[MAX];
bool check(int k)
{
	for(int i=1;i<=n;++i)a[i]=0;
	for(int i=1;i<=k;++i)a[l[i]]+=d[i],a[r[i]+1]-=d[i];
	for(int i=1;i<=n;++i){a[i]+=a[i-1];if(a[i]>s[i])return false;}
	return true;
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;++i)s[i]=read();
	for(int i=1;i<=m;++i)d[i]=read(),l[i]=read(),r[i]=read();
	int l=1,r=m,ret=m+1;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check(mid))l=mid+1;
		else ret=mid,r=mid-1;
	}
	if(ret>m)puts("0");else printf("-1\n%d\n",ret);
	return 0;
}
疫情控制 blockade
好题。
不难发现可以二分答案。考虑如何\(check\)。
首先如果一支军队不能走到根节点那么显然它就停在能够到达的深度最浅的位置一定最优。那么军队分为两类,一类可以到达根节点,即可以控制其他子树,另外一类则不行,那么停留在最优位置不动。接下来,先不考虑可以控制其他子树的军队,\(dfs\)一遍,看看哪些子树需要控制。显然控制在根节点的儿子位置一定最优。显然所有可以控制其他子树的军队全部到达根节点,然后按照剩余移动时间排序。所有需要被覆盖的子树按照距离排序。从小往大一一匹配即可。注意一个问题,考虑一支军队的时候,如果它过来的那个子树还未被覆盖,那么优先覆盖他过来的那棵子树。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define MAX 50050
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
struct Line{int v,next,w;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
int n,m,top[MAX],a[MAX];
ll s[16][MAX],dep[MAX];
int p[16][MAX];
void dfs(int u,int ff)
{
	dep[u]=dep[ff]+s[0][u];
	for(int i=1;i<16;++i)
		p[i][u]=p[i-1][p[i-1][u]],s[i][u]=s[i-1][u]+s[i-1][p[i-1][u]];
	for(int i=h[u];i;i=e[i].next)
		if(e[i].v!=ff)
			p[0][e[i].v]=u,s[0][e[i].v]=e[i].w,dfs(e[i].v,u);
}
void dfs(int u,int ff,int id)
{
	top[u]=id;
	for(int i=h[u];i;i=e[i].next)
		if(e[i].v!=ff)dfs(e[i].v,u,id);
}
int Move(int u,ll x)
{
	for(int i=15;~i;--i)
		if(p[i][u]&&x>=s[i][u])
			x-=s[i][u],u=p[i][u];
	return u;
}
struct Army{int fr;ll t;}q[MAX];
bool operator<(Army a,Army b){return a.t<b.t;}
bool cmp(int a,int b){return dep[a]<dep[b];}
bool vis[MAX];
void dfs2(int u,int ff)
{
	bool fl=true;int son=0;
	for(int i=h[u];i;i=e[i].next)
		if(e[i].v!=ff)
		{
			dfs2(e[i].v,u);++son;
			if(!vis[e[i].v])fl=false;
		}
	if(fl&&son)vis[u]=true;
}
int nd[MAX];
bool check(ll t)
{
	int tot=0,sum=0;memset(vis,0,sizeof(vis));
	for(int i=1;i<=m;++i)
	{
		int x=Move(a[i],t);
		if(x==1)q[++tot]=(Army){top[a[i]],t-dep[a[i]]};
		else vis[x]=true;
	}
	dfs2(1,0);if(vis[1])return true;
	for(int i=h[1];i;i=e[i].next)
		if(!vis[e[i].v])nd[++sum]=e[i].v;
	sort(&q[1],&q[tot+1]);
	sort(&nd[1],&nd[sum+1],cmp);
	if(tot<sum)return false;int j=1;
	for(int i=1;i<=tot;++i)
	{
		if(!vis[q[i].fr]){vis[q[i].fr]=true;continue;}
		while(j<=sum&&vis[nd[j]])++j;
		if(q[i].t>=dep[nd[j]])vis[nd[j]]=true;
	}
	while(j<=sum&&vis[nd[j]])++j;
	return j>sum;
}
int main()
{
	n=read();
	for(int i=1;i<n;++i)
	{
		int u=read(),v=read(),w=read();
		Add(u,v,w);Add(v,u,w);
	}
	dfs(1,0);
	for(int i=h[1];i;i=e[i].next)dfs(e[i].v,1,e[i].v);
	m=read();
	for(int i=1;i<=m;++i)a[i]=read();
	ll l=0,r=5e13,ret=-1;
	while(l<=r)
	{
		ll mid=(l+r)>>1;
		if(check(mid))ret=mid,r=mid-1;
		else l=mid+1;
	}
	printf("%lld\n",ret);
	return 0;
}
												
											NOIP2012题解的更多相关文章
- NOIP2012 题解
		
Vigenère 密码 这个名字实在打不来... 题解:模拟 #include <cstdio> #include <cstring> +; bool cj; int cl, ...
 - [NOIP补坑计划]NOIP2012 题解&做题心得
		
场上预计得分:100+90+70+100+100+3060=490520(省一分数线245) 题解: D1T1 Vigenère 密码 题面 水题送温暖~~ #include<iostream& ...
 - NOIP2012 疫情控制 题解(LuoguP1084)
		
NOIP2012 疫情控制 题解(LuoguP1084) 不难发现,如果一个点向上移动一定能控制更多的点,所以可以二分时间,判断是否可行. 但根节点不能不能控制,存在以当前时间可以走到根节点的点,可使 ...
 - [NOIP2012提高]借教室 题解(二分答案+差分)
		
[NOIP2012提高&洛谷P1083]借教室 Description 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室 ...
 - noip2012开车旅行 题解
		
题目大意: 给出n个排成一行的城市,每个城市有一个不同的海拔.定义两个城市间的距离等于他们的高度差的绝对值,且绝对值相等的时候海拔低的距离近.有两个人轮流开车,从左往右走.A每次都选最近的,B每次都选 ...
 - [NOIP2012]国王游戏 题解
		
题目大意: n个人排成一排,排头固定,其他可以变.每一个人左右手都有一个整数,一个人的分数为他所有前面的人左手上的数的乘积除以他右手上的数(向下取整),求在整列中最大分数的最小值. 思路: 首先,一切 ...
 - [NOIP2012]借教室 题解
		
题目大意: 有一个n个数的数列,m个操作,第i个操作使[li,ri]区间建di,问第几个操作使数列中出现负数. 思路: 暴力显然过不了,那么就可以优化了,不难想到线段树,显然需要良好的姿势,那么就差分 ...
 - 【数学】【NOIp2012】同余方程 题解 以及 关于扩展欧几里得与同余方程
		
什么是GCD? GCD是最大公约数的简称(当然理解为我们伟大的党也未尝不可).在开头,我们先下几个定义: ①a|b表示a能整除b(a是b的约数) ②a mod b表示a-[a/b]b([a/b]在Pa ...
 - 【NOIP2012】DAY1+DAY2题解
		
不贴代码的原因是我的代码在初中机房.忘记带过来了. DAY 1 T1随便搞,但是字符串相关的题我经常犯蠢 T2 一个结论题,OAO但是需要高精度写. 具体就是按左手的数除右手的数(还是怎么的来着)排个 ...
 
随机推荐
- sql server2016里面的json功能 - 转
			
测试一下基本的,从查询结果里面构造一个json 的格式 create table t1(ID int identity,name nvarchar(50),Chinese int ,Math int) ...
 - 从github  checkout子文件夹
			
1.将远程项目加载到指定目录:$git init; $git remote add -f origin url2.使用SparseCheckout模式:$git config core.sparsec ...
 - NOIP2018 模拟赛(二十二)雅礼NOI
			
Preface 这次的题目都是NOI+的题,所以大家的分数都有点惨烈. 依靠T1大力骗分水到Rank2 所以想看正解的话看这里吧 A. 「雅礼NOI2018模拟赛(一) Day1」树 看一眼题目感觉十 ...
 - Luogu  P4317 花神的数论题
			
也是一道不错的数位DP,考虑先转成二进制后再做 转化一下问题,考虑统计出\([1,n]\)中在二进制下有\(i\)个\(1\)的方案数\(cnt_i\),那么答案显然就是\(\prod i^{cnt_ ...
 - AT2134 Zigzag MST
			
题面 题解 这个题目主要是连边很奇怪,但是我们可以发现一个性质:权值是递增的. 于是像下图的连边:(加边方式为\((A_1, B_1, 1)\)) 其实可以等价于如下连边: 于是我们将其变成了在环上连 ...
 - C#的RSA加密解密签名,就为了支持PEM PKCS#8格式密钥对的导入导出
			
差点造了一整个轮子 .Net Framework 4.5 里面的RSA功能,并未提供简单对PEM密钥格式的支持(.Net Core有咩?),差点(还远着)造了一整个轮子,就为了支持PEM PKCS#8 ...
 - c#基础系列1---深入理解值类型和引用类型
			
"大菜":源于自己刚踏入猿途混沌拾起,自我感觉不是一般的菜,因而得名"大菜",于自身共勉. 不知不觉已经踏入坑已10余年之多,对于c#多多少少有一点自己的认识, ...
 - jackjson-databind-2.9.3 笔记
			
问题 客户端请求: {"skip":0,"take":10,"corpName":"","cityCode&q ...
 - SCP和Rsync远程拷贝的几个技巧
			
scp是secure copy的简写,用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的.可能会稍微影响一下速度.当你服务器 ...
 - linux-文件流4种读取方式
			
第二种方式 第三种 第四种: 小括号在管道符的右边开辟了两个子进程 大括号在管道符的右边开辟了一个子进程, export 用来导出子进程的 num 还可以借助外部文件进行 七步扩展: