zoukankan      html  css  js  c++  java
  • 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没有什么太大的区别。

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

  • 相关阅读:
    MySQL数据库可以用任意ip连接访问的方法
    Docker packaging guide for Python
    Alpine makes Python Docker builds 50× slower, and images 2× larger
    hasura graphql-engine v1.0 发布了
    edgedb 1.0 Alpha 2 了
    aceql-http docker 试用
    deno学习五 typescript + vscode 集成
    makeself 试用
    poolifier nodejs 线程池工具
    Java Command Line Parsers Comparison
  • 原文地址:https://www.cnblogs.com/Gloid/p/10440264.html
Copyright © 2011-2022 走看看