题目链接

感觉这样的题真的称得上是鬼斧神工啊,\(\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. 学习CSS布局 - max-width

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. IDEA 创建和使用tomcat

    一.创建一个普通web项目,步骤略,如下图. 二.配置项目相关信息. 1.通过如下方式在Artifacts下添加我们的项目. 2.选中我们的项目. 3.修改项目的默认输出位置,可根据需要修改. 4.如 ...

  3. C# 邮箱的使用

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Configurat ...

  4. Attention[Content]

    0. 引言 神经网络中的注意机制就是参考人类的视觉注意机制原理.即人眼在聚焦视野区域中某个小区域时,会投入更多的注意力到这个区域,即以"高分辨率"聚焦于图像的某个区域,同时以&qu ...

  5. python 方法调用

    获取当前时间 today=time.strftime('%Y-%m-%d',time.localtime(time.time())) 取得时间相关的信息的话,要用到python time模块,pyth ...

  6. 把DataTable转换为List<T>

    前一篇有学习过<把List<T>转换为DataTable>http://www.cnblogs.com/insus/p/8043173.html 那此篇,将是学习反向,把Dat ...

  7. wpf项目打开多个窗体在任务栏只有一个任务

    原文:wpf项目打开多个窗体在任务栏只有一个任务 如果在wpf里,在一个父窗体上打开子窗体,只在任务栏显示一个任务,不是qq聊天窗口俩人聊天人显示俩给那样,只能显示 一个 private void B ...

  8. Ionic项目的建立

    Ionic建立android项目的过程 1.cmd到目标盘文件,此处为D:\Dev\sourcecode\IonicApp\FlexApp\CaseStudy,执行ionic start CaseSt ...

  9. Jlink使用技巧之烧写SPI Flash存储芯片

    前言 大多数玩单片机的人都知道Jlink可以烧写Hex文件,作为ARM仿真调试器,但是知道能烧写SPI Flash的人应该不多,本篇文章将介绍如何使用JLink来烧写或者读取SPI Flash存储器, ...

  10. Docker 快速验证 HTML 导出 PDF 高效方案

    需求分析 项目中用到了 Echarts,想要把图文混排,当然包括 echarts 生成的 Canvas 图也导出 PDF. 设计和实现时,分析了 POI.iText.freemaker.world 的 ...