HDU3693 Math Teacher's Homework

一句话题意

给定$n, k以及m_1, m_2, m_3, ..., m_n$求$x_1 \oplus x_2 \oplus x_3 \oplus ... \oplus x_n == K(x_1 \leq m_1, x_2 \leq m_2...)$ 的方案数。

题解

一开始口糊了一下,然后写代码的时候发现不少东西没考虑周到,于是就看起了题解。

我们首先需要发现一个重要的性质:

如果某一位上不受m限制(也就是选0或选1都可以)那么无论其它数的这一位位选什么都可以通过这一位来变成结果和K的这一位相等

为了避免来自$x <= m$的麻烦,我们首先让$m ++$, 使条件变为$x < m$。

然后按照数位dp的套路对位分析。

首先假设我们处理到了第j位,然后从高位到$j + 1$位都已经到了最大值

然后第$j$位由于要小于m,所以m的这一位必然1,然后j的这一位必然是0

然后按照套路我们发现如果这一位我们选了0,那么后面的位随便选都不会大于m

为了方便dp,我们令每一位最早允许随便选的那个$x_i$为$A_j$,这个数将在后面被限制以使其它自由位达到K上对应位的要求

我们记第j位上的第i个数字为自由的,当且仅当这个位不是被m限制了(即第i个数从高位枚举到第一个比m小的位置),且不是那些被最早选择(上一行的定义)限制的数字。

然后每一位上的方案数就是$2^{自由数个数-1}$

于是我们设$dp[i][j][0/1]$表示第i个数的“第i个数从高位枚举到第一个比m小的位置”为j,此位的异或值为0/1

下面我们记

$num[i][j]$为第i个数字第j位

$sum[i][j]$为j位上从第一个数字异或到第i个数字的结果

然后分情况(自由数位置)讨论从状态$dp[i - 1][k][r]$(注意大小写)(注意下面$2^x$的下标)转移,若

m此位可以有不同限制,即$num[i][j] == 1$

$j < k$:$dp[i][j][sum[i - 1][j]] += dp[i - 1][k][r] * 2^k$

$j > k$:$dp[i][k][r \oplus sum[i - 1][j]] += dp[i - 1][k][r] * 2^j$

$j == k$:$dp[i][j][r] += dp[i - 1][k][r] * 2^k$

最后要求$k[j] == sum[n][j]$的时候才能统计入答案

(然而我并不知道怎么用Latex打出'^' ......)

代码如下:

 #include <cstdio>

 #include <bitset>
#include <cstring> using namespace std; char buf[], *pc = buf; inline void Main_Init(){
static bool inited = false;
if(inited) fclose(stdin), fclose(stdout);
else {
fread(buf, , , stdin);
inited = true;
}
} inline int read(){
int num = ;
char c;
while((c = *pc ++) < );
while(num = num * + c - , (c = *pc ++) >= );
return num;
} //Source Code const int MAXN = ;
const int MAXM = ;
const int MODS = ; int n, ans;
int x[MAXN];
unsigned int bin[MAXM];
int dp[MAXN][MAXM][]; bitset<> K, num[MAXN], sum[MAXN]; int main(){
Main_Init();
for(int i = ; i < ; i++) bin[i] = << i;
while(n = read(), n){
K = read();
for(int i = ; i <= n; i++)
num[i] = x[i] = read() + ;
memset(sum, , sizeof(sum)), memset(dp, , sizeof(dp));
ans = ;
dp[][][] = ;
for(int j = ; j < ; j++) sum[][j] = num[][j];
for(int i = ; i <= n; i++)
for(int j = ; j < ; j++)
sum[i][j] = sum[i - ][j] ^ num[i][j];
for(int i = ; i <= n; i++){
for(int j = ; j < ; j++){
if(!num[i][j]) continue;
for(int k = ; k < ; k++){
for(int r = ; r < ; r++){
if(dp[i - ][k][r]){
if(j > k) dp[i][j][sum[i - ][j]] = (dp[i][j][sum[i - ][j]] + 1ll * dp[i - ][k][r] * bin[k]) % MODS;
else if(j < k) dp[i][k][r ^ num[i][k]] = (dp[i][k][r ^ num[i][k]] + 1ll * dp[i - ][k][r] * bin[j]) % MODS;
else dp[i][j][r] = (dp[i][j][r] + 1ll * dp[i - ][k][r] * bin[k]) % MODS;
}
}
}
}
}
for(int i = ; i >= && K[i + ] == sum[n][i + ]; i--)
ans = (1ll * ans + dp[n][i][K[i]]) % MODS;
printf("%d\n", ans);
}
Main_Init();
return ;
}

HDU3693 Math Teacher's Homework ---- 数位DP的更多相关文章

  1. Math teacher's homework

    Title:[Math teacher's homework] Description 题目大意:给你n个数m1,m2...mn,求满足X1 xor X2 xor ... xor Xn=k,0< ...

  2. POJ 3986 Math teacher's homework

    题目 给出\(n,m_1,m_2,...,m_n\),求\(x_1 xor x_2 xor ... xor x_n=k (0 \leq x_i \leq m_i)\)的解的数量.二进制位数小于\(32 ...

  3. 题解 Math teacher's homework

    题目传送门 题目大意 给出 \(n,k\) 以及 \(a_{1,2,...,n}\) ,求有多少个 \(m_{1,2,...,n}\) 满足 \(\forall i,m_i\le a_i\) 且 \( ...

  4. hiho1259 A Math Problem (数位dp)

    题目链接:http://hihocoder.com/problemset/problem/1259 题目大意:g(t)=(f(i)%k=t)的f(i)的个数 求所有的(0-k-1)的g(i)的异或总值 ...

  5. 2018.09.28 hdu5435A serious math problem(数位dp)

    传送门 数位dp卡常题. 写了一发dfs版本的发现过不了233. 于是赶紧转循环版本. 预处理出f数组. f[i][j]f[i][j]f[i][j]表示前i位数异或和为j的方案数. 然后每次直接数位d ...

  6. HDU 4507 (鬼畜级别的数位DP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4507 题目大意:求指定范围内与7不沾边的所有数的平方和.结果要mod 10^9+7(鬼畜の元凶) 解题 ...

  7. HDU 2089 数位dp入门

    开始学习数位dp...一道昨天看过代码思想的题今天打了近两个小时..最后还是看了别人的代码找bug...(丢丢) 传说院赛要取消 ? ... 这么菜不出去丢人也好吧~ #include<stdi ...

  8. hdu5787(数位dp)

    基础的数位dp,才发现今天才终于彻底搞懂了数位dp... // // main.cpp // hdu5787.1 // // Created by New_Life on 16/8/10. // Co ...

  9. [kuangbin带你飞]专题十五 数位DP

            ID Origin Title   62 / 175 Problem A CodeForces 55D Beautiful numbers   30 / 84 Problem B HD ...

随机推荐

  1. Kubernetes Service

    目录 基本概念 服务发现与负载均衡 配置Service 创建一个ClusterIP类型的Service 创建一个指定ClusterIP的Service 创建一个headless service 创建一 ...

  2. Linux-Xshell会话保持

    1.Xshell客户端设置 2.服务端设置 修改/etc/ssh/sshd_config文件,找到 ClientAliveInterval 0和ClientAliveCountMax 3并将注释符号( ...

  3. js 正则之 检测素数

    相信很多人应该看过这篇文章,我第一次看到的时候是11年的样子,那时候学vbs的时候看过这个问题.原文<检查素数的正则表达式>,在文章里已经解释了他是怎么判断的,我就不啰嗦了.我们来说说 j ...

  4. Spring Mvc + Maven + yuicompressor 使用 profile 来压缩 javascript ,css 文件; (十)

    profile相关知识点: 在开发项目时,设想有以下场景: 你的Maven项目存放在一个远程代码库中(比如github),该项目需要访问数据库,你有两台电脑,一台是Linux,一台是Mac OS X, ...

  5. 20155216 2016-2017-2 《Java程序设计》第八周学习总结

    20155216 2016-2017-2 <Java程序设计>第八周学习总结 教材学习内容总结 认识NIO Java NIO 由以下几个核心部分组成: Channels Buffers S ...

  6. Oracle 修改用户名

    1.开始- 运行 - 输入“CMD” 确定 2.在弹出来的窗口中,输入:SQLPLUS / AS SYSDBA  回车 3.然后,用命令修改:alter user 用户名 identified by ...

  7. A - Jugs ZOJ - 1005 (模拟)

    题目链接:https://cn.vjudge.net/contest/281037#problem/A 题目大意:给你a,b,n.a代表第一个杯子的容量,b代表第二个杯子的容量,然后一共有6种操作.让 ...

  8. Ubuntu GNOME单击任务栏图标最小化设置

    在Ubuntu GNOME的发行版中,桌面使用的是GNOME,GNOME可以像Windows那样有一个底部任务栏,在Ubuntu GNOME中它称为 dash to dock,如下图: Windows ...

  9. Shell脚本中实现切换用户并执行命令操作【转】

    第一种方法 cat test.sh #!/bin/bashsu - test <<EOFpwd;exit;EOF 执行结果图: 第二种方法 当然也可以用下面的命令来执行 复制代码代码如下: ...

  10. .NET C#错误:所生成项目的处理器框架“MSIL”与引用“wdapi_dotnet1021”的处理器架构“AMD64”不匹配

    .NET C#错误:所生成项目的处理器框架“MSIL”与引用“wdapi_dotnet1021”的处理器架构“AMD64”不匹配. 直接在项目右键属性->生成->x64. 即可解决