题目链接

感觉这样的题真的称得上是鬼斧神工啊,\(\text{OI}\)中能多一些这样的题目就太好了。

题意:

有一个二维的三角坐标系,大概如图所示(图是从atcoder里偷下来的):

坐标系上的每个整点处都有一盏灯,初始时只有一盏灯亮着。每次可以选择三个整点\((x,y)\),\((x,y+1)\),\((x+1,y)\)(即一个底边向下的正三角形),将这三盏灯的开关状态反转。现在给出若干次反转操作后所有亮着的\(n\)盏灯的坐标,求最初亮着的是哪一盏灯。\(n\leq 10^4\),\(-10^{17}\leq 坐标\leq 10^{17}\)。

题解:

我们考虑将从某一盏灯开始,不断通过向下反转将在\(y=c\)上的灯转移到\(y=c-1\)上。可以发现如果我们从\((0,0)\)开始向下转移\(c\)次,每一行的亮灯状态就是帕斯卡三角在模\(2\)意义下的结果,结合卢卡斯定理,可以发现\(y=-c\)上只有满足\(0\leq x\leq c\)且\(x\subseteq c\)的\((x,-c)\)是亮的。那么不难发现此时\((0,-c)\)和\((c,-c)\)一定是亮的,于是我们只要将所有亮着的灯向下转移到同一条足够低的直线上,再计算出这条直线上亮着的灯中最左端和最右端的点,就可以知道原来的点是什么。

说的好听,怎么计算左右端点呢?

我们先来研究一下帕斯卡三角在模\(2\)意义下有什么性质。如果我们将模\(2\)余\(1\)的点看作黑点,否则看作白点,那么帕斯卡三角是长这样的(偷自维基百科):

可以发现这是一个类似分形的结构,同时每一个三角形的边长都是\(2^k\)。那么考虑从这一行的任意一个亮着的\((x,y)\)开始向右移动,对于\(k=60,59,\dots,0\),如果\((x,y+2^k)\)是亮着的,那么移动到\((x,y+2^k)\),这相当于移动至右边的一个同构三角形的等价位置上。可以证明这一定可以移动到右端点。左端点也是类似的。判断一个点是否是亮着的也很简单,只需要\(O(n)\)扫描每个点即可。

于是我们得到了一个优秀的\(O(n\log MAX)\)的做法,其中\(MAX\)表示坐标范围。假的。

上面这个做法的问题在于我们无法快速找到一行中的一个会亮着的点!那么怎么高效的找到一个呢?

再考虑帕斯卡三角形的一个性质:对于第\(n\)行,对于\(k=0,1,2\),至少存在一个\(k\)使得\(\sum_{x\equiv k(\bmod\ 3)}{n\choose x}\equiv 1(\bmod \ 2)\),由归纳法保留上一行模\(3\)的和数组向下转移即可证明。假设我们可以在很快的时间里计算对于\(l\leq x\leq r\)且\(x\equiv k(\bmod\ 3)\)的\(x\),\((x,-c)\)是亮着的点数是奇数还是偶数,那么就可以通过二分的方法,每次选择点数是奇数的那一半继续做即可。由于左右两边的总点数是奇数因此这一半是一定存在的。

考虑怎么解决这个问题,显然在模\(2\)下每个点可以分开计算。那么对每个点考虑数位\(dp\),状态只需要记已经确定了几位,是否受数位的限制以及当前数在模\(3\)意义下余多少即可,结合卢卡斯定理可以设计转移。这么做复杂度是\(O(n\log MAX)\)的,结合二分,我们可以在\(O(n\log^2 MAX)\)的时间内找到一个亮着的点。于是我们就在\(O(n\log^2 MAX)\)的时间内解决了问题。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<utility>
using std::max;
using std::min;
using std::pair;
using std::make_pair;
typedef long long ll;
const int N=1e4+5;
int n;
ll x[N],y[N];
int res[3];
int dp[64][2][3];
inline void calc(ll c,ll x,ll y,ll r)
{
ll n=x-c;
register int i,j,k;
r-=y;
if(r<0)
return res[0]=res[1]=res[2]=0,void();
memset(dp,0,sizeof(dp));
dp[63][1][0]=1;
for(i=63;i>0;i--)
if(!(n>>(i-1)&1))
{
for(j=0;j<3;j++)
{
if(dp[i][0][j])
dp[i-1][0][(j*2)%3]^=1;
if(dp[i][1][j])
{
if(r>>(i-1)&1)
dp[i-1][0][(j*2)%3]^=1;
else
dp[i-1][1][(j*2)%3]^=1;
}
}
}
else
{
for(j=0;j<3;j++)
{
if(dp[i][0][j])
{
dp[i-1][0][(j*2)%3]^=1;
dp[i-1][0][(j*2+1)%3]^=1;
}
if(dp[i][1][j])
{
if(r>>(i-1)&1)
dp[i-1][0][(j*2)%3]^=1,dp[i-1][1][(j*2+1)%3]^=1;
else
dp[i-1][1][(j*2)%3]^=1;
}
}
}
y=(y%3+3)%3;
res[y]=dp[0][0][0]^dp[0][1][0];
res[(y+1)%3]=dp[0][0][1]^dp[0][1][1];
res[(y+2)%3]=dp[0][0][2]^dp[0][1][2];
return;
}
int lres[3],rres[3],mres[3];
inline ll epc(ll c)
{
int k;
ll l=-1000000000000000000ll,r=1000000000000000000ll,mid;
register int i;
rres[0]=rres[1]=rres[2]=0;
for(i=1;i<=n;i++)
{
calc(c,x[i],y[i],r);
rres[0]^=res[0];rres[1]^=res[1];rres[2]^=res[2];
}
lres[0]=lres[1]=lres[2]=0;
for(i=0;i<3;i++)
if(rres[i])
{
k=i;
break;
}
while(l<r)
{
mid=(l+r)>>1;
mres[0]=mres[1]=mres[2]=0;
for(i=1;i<=n;i++)
{
calc(c,x[i],y[i],mid);
mres[0]^=res[0];mres[1]^=res[1];mres[2]^=res[2];
}
if(mres[k]^lres[k])
r=mid,memcpy(rres,mres,sizeof(int)*3);
else
l=mid+1,memcpy(lres,mres,sizeof(int)*3);
}
return l;
}
inline bool light(ll x,ll y)
{
int res=0;
ll xx,yy,n,m;
register int i;
for(i=1;i<=::n;i++)
{
xx=::x[i];yy=::y[i];
n=xx-x;m=y-yy;
if(m<0||m>n)
continue;
res^=((n|m)==n);
}
return res;
}
inline void solve(ll c,pair<ll,ll> &a)
{
ll k=epc(c),lk=k,rk=k;
// fprintf(stderr,"%lld\n",k);
register ll i;
for(i=1ll<<62;i;i>>=1)
if(light(c,lk-i))
lk-=i;
for(i=1ll<<62;i;i>>=1)
if(light(c,rk+i))
rk+=i;
a.first=c+(rk-lk);a.second=lk;
return;
}
signed main()
{
pair<ll,ll> a;
register int i;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%lld%lld",&x[i],&y[i]);
solve(-100000000000000000,a);
printf("%lld %lld\n",a.first,a.second);
return 0;
}

AtCoder WTF 2019 C2. Triangular Lamps Hard的更多相关文章

  1. AtCoder ExaWizards 2019 简要题解

    AtCoder ExaWizards 2019 简要题解 Tags:题解 link:https://atcoder.jp/contests/exawizards2019 很水的一场ARC啊,随随便便就 ...

  2. AtCoder diverta 2019 Programming Contest 2

    AtCoder diverta 2019 Programming Contest 2 看起来我也不知道是一个啥比赛. 然后就写写题解QWQ. A - Ball Distribution 有\(n\)个 ...

  3. AtCoder ExaWizards 2019 D Modulo Operations

    题意 给出一个长度为\(n\)的数列和数字\(X\),对于数列的每一种排列,其权值\(X\)依次对排列中的数取模,求出\(n!\)种情况最后剩下的数的权值和 分析 如果大的数字排在小的数字后面,那么大 ...

  4. AtCoder M-SOLUTIONS 2019 Task E. Product of Arithmetic Progression

    problem link Official editorial: code: int main() { #if defined LOCAL && !defined DUIPAI ifs ...

  5. AtCoder Beginner Contest 133-C - Remainder Minimization 2019

    https://atcoder.jp/contests/abc133/tasks/abc133_c 思路:由于L,R区间太大,所以不能暴力枚举.由于求(i*j)%2019的最小值,那么2019的倍数对 ...

  6. [AtCoder] NIKKEI Programming Contest 2019 (暂缺F)

    [AtCoder] NIKKEI Programming Contest 2019   本来看见这一场的排名的画风比较正常就来补一下题,但是完全没有发现后两题的AC人数远少于我补的上一份AtCoder ...

  7. [AtCoder] Yahoo Programming Contest 2019

    [AtCoder] Yahoo Programming Contest 2019   很遗憾错过了一场 AtCoder .听说这场是涨分场呢,于是特意来补一下题. A - Anti-Adjacency ...

  8. 【AtCoder】Tenka1 Programmer Contest 2019

    Tenka1 Programmer Contest 2019 C - Stones 题面大意:有一个01序列,改变一个位置上的值花费1,问变成没有0在1右边的序列花费最少多少 直接枚举前i个都变成0即 ...

  9. 【AtCoder】ExaWizards 2019

    ExaWizards 2019 C - Snuke the Wizard 发现符文的相对位置不变,直接二分某个位置是否到达最左或最右来计算 #include <bits/stdc++.h> ...

随机推荐

  1. java 面向对象内部类

    1.内部类概念:将一个类定义在另一个类的内部,该类就称为内部类 类中定义的内部类特点1) 内部类作为外部类的成员,可以直接访问外部类的成员(包括 private 成员),反之则不行.2) 内部类做为外 ...

  2. 浅谈UI自动化测试

    最近一直在学习python,正好部门技术结构调整,就开始了点工向UI自动化测试的转变,我要说瞌睡来了就掉枕头么? 不过还好,可以将python的学习成果在自动化测试中实践... 1.about自动化测 ...

  3. docker数据卷管理及网络基础配置

    数据卷 数据卷容器 数据卷迁移数据 端口映射 容器间通信 数据卷的管理 当需要查看容器内应用产生的数据或者把容器内数据备份及多个容器数据共享.有两种方式,数据卷以及数据卷容器. 数据卷 数据卷是一个可 ...

  4. java JDK安装教程

    JAVA_HOME G:\JDK\java7\jdk1.7.0_80    根据自己的哈     ;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin 然后找到CLASSPATH ...

  5. 将当前的Ubuntu系统封装成为可以安装(发布)的iso镜像

    将当前的Ubuntu系统封装成为可以安装(发布)的iso镜像 在使用以上方法安装依赖的时候xresprobe 会找不到安装地址,采用下面的方式: Package xresprobe is not in ...

  6. vue 首页背景图片加载完成前增加 loading 效果 -- 使用 new Image() 实现

    1. 创建 loading 公用组件 <template> <div class="load-container"> <div class=" ...

  7. 解密自动CPS变换

    7.2 1 前言 我最一开始听到 CPS 变换这个词是在王垠的博客里 (请求不要喷我),就是那篇他第一次宣传他的40行代码的文章. 我当时什么都看不懂,所以没太注意,不过我也正在学程序语言方面的东西, ...

  8. python报错问题解决:'ascii' codec can't encode character

    之前部署了openstack虚拟化环境,有一天在使用nova list查看虚拟机的时候,突然报错!如下: [root@linux-node1 src]# nova listERROR (Unicode ...

  9. Visual Studio的安装与单元测试

    一.Visual Studio的安装 由于上学期重装了win10系统,以前使用的vc++6.0不能够正常使用,所以直接就安装了Visual Studio 2015,安装的时候就直接按照提示的步骤进行安 ...

  10. Daily Scrum NO.10

    工作概况 今天是两周正是开发的最后一个工作日,虽然也是编译的DEADLINE,但成员们还是较为积极.计划内的工作基本都能够完成:线程池.异常清理器和动态爬取的功能.异常清理器界面的第一版也在今晚做了出 ...