Codeforces Round #468 Div. 1

  D:首先考虑如果给定白棋位置,如何判断胜负。黑棋获胜需要四个方向都有能贴上白棋的棋子。由于每一轮都必须移动,显然先对平面黑白染色一下,只有与白棋所在格异色的黑棋才需要考虑。考虑让一个黑棋去贴上白棋某个方向,那么能贴上的条件是该方向坐标之差>另一方向坐标之差。因为如果其往这边逃的话,这样才有足够的时间冲过去拦住。若往其他方向逃,只要模仿其动作即可,处于逃跑方向的棋子会对其作出制裁。

  可以发现每个黑棋对每个位置的白棋都只有一种能将其锁死的方向,四个方向的分界线形成一个X形。于是现在要数的是被任意四个黑棋的不同方向包含的白棋数量。

  斜着的东西很难考虑,把坐标系旋转一下45°,分界线就变成了一个十字形,就看起来非常舒服了。这样的话扫描线扫过去,维护线两边的黑棋纵坐标上下界,两边上界取min下界取max即可得到该直线上的被锁死的白棋纵坐标上下界。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,u,v,mx[N],mn[N];
ll ans;
struct data
{
	int x,y;
	bool operator <(const data&a) const
	{
		return x<a.x;
	}
}a[N],b[N];
void solve(data *a,int n)
{
	for (int i=1;i<=n;i++)
	{
		int x=a[i].x,y=a[i].y;
		a[i].x=y-x,a[i].y=x+y;
	}
	sort(a+1,a+n+1);
	//for (int i=1;i<=n;i++) cout<<a[i].x<<' '<<a[i].y<<endl;
	mx[n+1]=-N,mn[n+1]=N;
	for (int i=n;i>=1;i--) mx[i]=max(mx[i+1],a[i].y),mn[i]=min(mn[i+1],a[i].y);
	int MX=-N,MN=N;
	int cur=0;
	for (int i=a[1].x;i<=a[n].x;i++)
	{
		while (cur<n&&i==a[cur+1].x) cur++,MX=max(MX,a[cur].y),MN=min(MN,a[cur].y);
		ans+=max(min(MX,mx[cur+1])-max(MN,mn[cur+1]),0);
	}
}
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("d.in","r",stdin);
	freopen("d.out","w",stdout);
#endif
	n=read();
	for (int i=1;i<=n;i++)
	{
		int x=read(),y=read();
		if ((x+y)%2) a[++u].x=x,a[u].y=y;
		else b[++v].x=x,b[v].y=y;
	}
	solve(a,u);solve(b,v);
	cout<<ans/4;
	return 0;
	//NOTICE LONG LONG!!!!!
}

  E:将每个限制存储在其右端点上,记录最靠右的li,0、li,1表示li,j到i至少要有一个j。设f[i][0/1]为第i位是0/1且满足所有右端点在i及i之前的限制的序列数量。转移考虑枚举最后一段连续0/1有多长,不妨考虑0,即有f[i][0]=Σf[j][1] (j>=max{lj~i,1})。前缀和一下,二分一下转移的最远点(直接移动指针难以更新max{l}),即可做到O(klogk)。

  注意到当一个点不存在限制时,f[i][0]=f[i][1]=f[i-1][0]+f[i-1][1]。如果连续一段没有限制,dp值会构成公比2的等比数列。于是考虑离散化后dp。然后应该和上面的dp没有什么太大的区别。

  可是为什么想想就很难写啊。咕咕咕。有缘再补(?)

原文地址:https://www.cnblogs.com/Gloid/p/10440264.html