(联考)noip91
作者:互联网
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。
枚举影分身,拿个指针去扫卷轴,对于当前扫到的卷轴有两种情况:
-
卷轴在影分身的右侧,那就直接往右走,如果不能走到,应去枚举下一个影分身,看是否能让它拾取此卷轴。
-
卷轴在影分身的左侧,要保证其能在拾取到上一个没能拾取到的最靠右的卷轴的前提下,尽可能的往右走。这样的话就可以先往左后往右,也可以先往右后往左。如果无法走到,那么下一个肯定也无法走到,直接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