ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

(联考)noip91

2021-11-08 07:31:19  阅读:117  来源: 互联网

标签:int noip91 mid 卷轴 freopen printf array 联考


T1

不难发现,答案就是第一类斯特林数。

递推公式:

\[\left[\begin{array}{l} n \\ k \end{array}\right]=\left[\begin{array}{l} n-1 \\ k-1 \end{array}\right]+(n-1)\left[\begin{array}{c} n-1 \\ k \end{array}\right] \]

不过考场上并不知道这玩意叫第一类斯特林数

T2

总区间个数为 \(\frac{n(n+1)}{2}\) 。

发现如果一个区间 \([l,r]\) 要产生贡献,则 \(s_{l}\neq s_{r}\) ,否则去掉两端的字符后再翻转,得到的字符串是一样的,这样的话就在总区间个数里算重了,需要减去。

所以直接扫一遍,每回减去当前位置上的字符之前出现的次数,这样没有算到翻转字符串长度为1的情况,最后再单独计算即可。

T3

同类合并显然,然后状压即可。

T4

考场上连二分答案都没有想到...

显然要先将影分身和卷轴排好序。

答案具有单调性,如果当前时间合法,那么比它大的肯定也合法。

问题在于如何 \(O(n)\) check。

枚举影分身,拿个指针去扫卷轴,对于当前扫到的卷轴有两种情况:

  1. 卷轴在影分身的右侧,那就直接往右走,如果不能走到,应去枚举下一个影分身,看是否能让它拾取此卷轴。

  2. 卷轴在影分身的左侧,要保证其能在拾取到上一个没能拾取到的最靠右的卷轴的前提下,尽可能的往右走。这样的话就可以先往左后往右,也可以先往右后往左。如果无法走到,那么下一个肯定也无法走到,直接return即可。

一些细节见code。

Code
#include<cmath>
#include<cstdio>
#include<cctype>
#include<algorithm>
using std::sort;
#define re register
const int MAX = 3e5+3;
const int INF = 1.4e9+3;
#define long long long
#define scanf oma=scanf
#define freopen file=freopen
int oma;
FILE* file;
namespace some
{
	struct stream
	{
		template<typename type>inline stream &operator >>(type &s)
		{
			bool w=0; s=0; char ch=getchar();
			while(!isdigit(ch)){ w|=ch=='-'; ch=getchar(); }
			while(isdigit(ch)){ s=(s<<1)+(s<<3)+(ch^48); ch=getchar(); }
			return s=w?-s:s,*this;
		}
	}cin;
	int n,m,res;
	int p1[MAX],p2[MAX];
	auto max = [](int a,int b) { return a>b?a:b; };
	#define debug(s) printf("%s\n",s)
}using namespace some;
namespace OMA
{
	auto check = [](int mid,int p = 0) -> bool
	{
		//if(mid==38) { printf("mid=%d\n",mid); }
		for(re int i=1,rec; i<=n; i++)
		{
			p++;
			//if(mid==38) { printf("now=%d p=%d\n",i,p); }
			if(p1[i]<p2[p])
			{
				rec = p1[i]+mid;
				if(rec<p2[p])
				{
					p--; // 如果当前无法拾取到,考虑看是否能让下一个拾取到,因为循环前有p++的操作,所以此处需减去当前影分身的+1
					//if(mid==38) { printf("???: i=%d p=%d\n",i,p); }
					//return 0;
				}
			}
			else if(p1[i]>p2[p])
			{
				if(p1[i]-p2[p]>mid)
				{
					//if(mid==38) { printf("i=%d\n",i); debug("shit"); }
					return 0; // 当前的无法拾取到其左边的卷轴,那么下一个也一定无法拾取到,所以直接return即可。
				}
				rec = max(mid-p1[i]+p2[p]*2,(mid+p1[i]+p2[p])/2);
			}
			//if(mid==38) { printf("before: p=%d i=%d to=%d\n",p,i,rec); }
			while(p<m&&p2[p+1]<=rec)
			{ p++; }
			if(p==m)
			{
				//if(mid==38) { printf("mid=%d i=%d to=%d\n",mid,i,rec); }
				return 1;
			}
			//if(mid==38) { printf("p=%d i=%d cmp=%d to=%d\n",p,i,p2[p],rec); }
		}
		//printf("p=%d\n",p);
		//if(mid==38) { debug("shit"); }
		return 0;
	};
	auto main = []() -> signed
	{
		//#define local
		#ifdef local
		//debug("look here! if you want submit,please closed this");
		freopen("node.in","r",stdin); //freopen("my.out","w",stdout);
		#endif
		freopen("duplication.in","r",stdin); freopen("duplication.out","w",stdout);
		cin >> n >> m;
		for(re int i=1; i<=n; i++)
		{ cin >> p1[i]; }
		for(re int i=1; i<=m; i++)
		{ cin >> p2[i]; }
		sort(p1+1,p1+1+n),sort(p2+1,p2+1+m);
		//for(re int i=1; i<=n; i++) { printf("%d ",p1[i]); } debug("");
		//for(re int i=1; i<=m; i++) { printf("%d ",p2[i]); } debug("");
		//printf("%d\n",p2[m]);
		//check(119);
		int l = 1,r = INF;
		while(l<=r)
		{
			int mid = l+r>>1;
			//printf("l=%d mid=%d r=%d\n",l,mid,r);
			if(check(mid))
			{ r = mid-1,res = mid; }
			else
			{ l = mid+1; }
		}
		printf("%d\n",res);
		return 0;
	};
}
signed main()
{ return OMA::main(); }

标签:int,noip91,mid,卷轴,freopen,printf,array,联考
来源: https://www.cnblogs.com/-OMA-/p/15522610.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有