【XSY2691】中关村 卢卡斯定理 数位DP

题目描述

  在一个\(k\)维空间中,每个整点被黑白染色。对于一个坐标为\((x_1,x_2,\ldots,x_k)\)的点,他的颜色我们通过如下方式计算:

  • 如果存在一维坐标是\(0\),则颜色是黑色。
  • 如果这个点是\((1,1,\ldots,1)\)(每一维都是\(1\)),这个点的颜色是白色
  • 如果这个点的\(k\)个前驱(任取一维坐标减\(1\))中的白点有奇数个,那么这个点的颜色就是白色,否则就是黑色

  给出一个\(k\)维超矩形,求这个矩形内的白点个数。

  \(k\leq 9,1\leq l_i\leq r_i\leq {10}^{15}\)

题解

  先把所有坐标\(-1\)。

  然后DP。

  设\(S=(x_1,x_2,\ldots,x_k)\)。

  设\(f_S\)为一个坐标为\(S\)点的颜色(\(1\)为白色,\(0\)为黑色)。

  \(f_S=f_{S_1}\oplus f_{S_2}\oplus \cdots \oplus f_{S_k}\)。其中\(S_1,S_2,\ldots,S_k\)为\(S\)的\(k\)个前驱。

  这个表达式同样可以看成\(f_S=(\sum_{i=1}^k f_{S_i})\mod 2\)。

  那么可以看出\(f_S\)就是从\((0,0,\ldots,0)\)走到\(S\)的方案数\(\mod 2\),就是\(\binom{x_1+x_2+\cdots+x_k}{x_1~x_2~\cdots~x_k}\mod 2\)。

  我们推广一下卢卡斯定理,就会发现\(f_S=1\)当且仅当\(x_1,x_2,\ldots,x_k\)之间两两and和为\(0\)。

  可以用数位DP计算这个东西。

  时间复杂度:\(O(3^{\log r})\)

  我偷懒写了\(O(4^{\log r})\)的做法。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<utility>
using namespace std;
typedef pair<int,int> pii;
int n,s;
pii a[110];
int f[110][110][110];
int xx[110];
int yy[110];
int m1,m2;
int d[110];
int gao(int x)
{
    return x?s/x:0x3fffffff;
}
int gao(int l,int r,int h)
{
    int &s=f[h][l][r];
    if(~s)
        return s;
    while(l<=r&&d[l]<=h)
        l++;
    while(l<=r&&d[r]<=h)
        r--;
    if(l>r)
        return s=0;
    int i;
    s=0x7fffffff;
    for(i=l;i<r;i++)
        s=min(s,gao(l,i,h)+gao(i+1,r,h));
    int hh=gao(xx[r]-xx[l]);
    if(hh<=yy[h])
        return s;
    int v=upper_bound(yy+1,yy+m2+1,hh)-yy-1;
    s=min(s,gao(l,r,v)+1);
    return s;
}
void solve()
{
    scanf("%d%d",&n,&s);
    int i;
    for(i=1;i<=n;i++)
    {
        scanf("%d%d",&a[i].first,&a[i].second);
        xx[i]=a[i].first;
        yy[i]=a[i].second;
    }
    sort(xx+1,xx+n+1);
    sort(yy+1,yy+n+1);
    m1=unique(xx+1,xx+n+1)-xx-1;
    m2=unique(yy+1,yy+n+1)-yy-1;
    memset(f,-1,sizeof f);
    for(i=1;i<=m1;i++)
        d[i]=0;
    for(i=1;i<=n;i++)
    {
        a[i].first=lower_bound(xx+1,xx+m1+1,a[i].first)-xx;
        a[i].second=lower_bound(yy+1,yy+m2+1,a[i].second)-yy;
        d[a[i].first]=max(d[a[i].first],a[i].second);
    }
    int ans=gao(1,m1,0);
    printf("%d\n",ans);
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
    #endif
    int t;
    scanf("%d",&t);
    while(t--)
        solve();
    return 0;
}

原文地址:https://www.cnblogs.com/ywwyww/p/8513580.html

时间: 2024-08-09 12:36:01

【XSY2691】中关村 卢卡斯定理 数位DP的相关文章

bzoj 1902: Zju2116 Christopher lucas定理 &amp;&amp; 数位DP

1902: Zju2116 Christopher Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 172  Solved: 67[Submit][Status][Discuss] Description 给定n个元素,要从中间选择m个元素有多少种方案呢?答案很简单,就是C(n,m).如果一个整数m(0≤m≤n),C(n,m)是某一个质数p的倍数,那么这个m就是讨厌的数字,现在给定了p和n,求有多少个讨厌的数字. Input 第一行是一个正整数n,(1

BZOJ4737 组合数问题 【Lucas定理 + 数位dp】

题目 组合数C(n,m)表示的是从n个物品中选出m个物品的方案数.举个例子,从(1,2,3)三个物品中选择两个物品可以有( 1,2),(1,3),(2,3)这三种选择方法.根据组合数的定义,我们可以给出计算组合数C(n,m)的一般公式: C(n,m)=n!/m!*(n?m)! 其中n!=1×2×?×n.(额外的,当n=0时,n!=1) 小葱想知道如果给定n,m和k,对于所有的0≤i≤n,0≤j≤min(i,m)有多少对(i,j)满足C(i,j)是k的倍数. 输入格式 第一行有两个整数t,k,其中

HUST 1569(Burnside定理+容斥+数位dp+矩阵快速幂)

传送门:Gift 题意:由n(n<=1e9)个珍珠构成的项链,珍珠包含幸运数字(有且仅由4或7组成),取区间[L,R]内的数字,相邻的数字不能相同,且旋转得到的相同的数列为一种,为最终能构成多少种项链. 分析:这是我做过的最为综合的一道题目(太渣了),首先数位dp筛选出区间[L,R]内的幸运数字总数,dp[pos]表示非限制条件下还有pos位含有的幸运数字个数,然后记忆化搜索一下,随便乱搞的(直接dfs不知会不会超时,本人做法900+ms险过,应该直接dfs会超时),再不考虑旋转相同的情况,可以

[hihocoder 1033]交错和 数位dp/记忆化搜索

#1033 : 交错和 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0,?a1,?...,?an?-?1,定义交错和函数: f(x)?=?a0?-?a1?+?a2?-?...?+?(?-?1)n?-?1an?-?1 例如: f(3214567)?=?3?-?2?+?1?-?4?+?5?-?6?+?7?=?4 给定 输入 输入数据仅一行包含三个整数,l,?r,?k(0?≤?l?≤?r?≤?1018,?|k|

数位dp/记忆化搜索

一.引例 #1033 : 交错和 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, ..., an - 1,定义交错和函数: f(x) = a0 - a1 + a2 - ... + ( - 1)n - 1an - 1 例如: f(3214567) = 3 - 2 + 1 - 4 + 5 - 6 + 7 = 4 给定 l, r, k,求在 [l, r] 区间中,所有 f(x) = k 的 x 的和,

hihoCoder #1033 : 交错和 [ 数位dp ]

传送门 #1033 : 交错和 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, ..., an - 1,定义交错和函数: f(x) = a0 - a1 + a2 - ... + ( - 1)n - 1an - 1 例如: f(3214567) = 3 - 2 + 1 - 4 + 5 - 6 + 7 = 4 给定 l, r, k,求在 [l, r] 区间中,所有 f(x) = k 的 x 的和,即

UOJ #86 mx的组合数 (数位DP+NTT+原根优化)

题目传送门 matthew99神犇的题解讲得非常清楚明白,跪烂Orzzzzzzzzzzzzz 总结一下,本题有很多重要的突破口 1.Lucas定理 看到n,m特别大但模数特别小时,容易想到$lucas$定理 $C_{n}^{m}=C_{n/p}^{m/p}\cdot C_{n\;mod\;p}^{m\;mod\;p}\;(mod\;p)$ 但普通的$lucas$显然不适用于多次计算,我们可以把$lucas$定理展开 我们把$n$和$m$都看成两个$p$进制数$a$和$b$ $C_{n}^{m}=

51Nod 1009 数字1的个数 | 数位DP

题意: 小于等于n的所有数中1的出现次数 分析: 数位DP 预处理dp[i][j]存 从1~以j开头的i位数中有几个1,那么转移方程为: if(j == 1) dp[i][j] = dp[i-1][9]*2+pow(10,i-1);else dp[i][j] = dp[i-1][9]+dp[i][j-1]; 然后注意下对于每个询问统计的时候如果当前位为1需要额外加上他后面所有位数的个数,就是n%pow(10,i-1); 这样总复杂度log(n)*10 #include <bits/stdc++.

HDU 3555 Bomb (数位DP)

数位dp,主要用来解决统计满足某类特殊关系或有某些特点的区间内的数的个数,它是按位来进行计数统计的,可以保存子状态,速度较快.数位dp做多了后,套路基本上都差不多,关键把要保存的状态给抽象出来,保存下来. 简介: 顾名思义,所谓的数位DP就是按照数字的个,十,百,千--位数进行的DP.数位DP的题目有着非常明显的性质: 询问[l,r]的区间内,有多少的数字满足某个性质 做法根据前缀和的思想,求出[0,l-1]和[0,r]中满足性质的数的个数,然后相减即可. 算法核心: 关于数位DP,貌似写法还是