BZOJ 1662: [Usaco2006 Nov]Round Numbers 圆环数(数位DP+恶心细节)

BZOJ 1662: [Usaco2006 Nov]Round Numbers 圆环数

Time Limit: 5 Sec  Memory Limit: 64 MB

Description

正如你所知,奶牛们没有手指以至于不能玩“石头剪刀布”来任意地决定例如谁先挤奶的顺序。她们甚至也不能通过仍硬币的方式。 所以她们通过"round number"竞赛的方式。第一头牛选取一个整数,小于20亿。第二头牛也这样选取一个整数。如果这两个数都是 "round numbers",那么第一头牛获胜,否则第二头牛获胜。 如果一个正整数N的二进制表示中,0的个数大于或等于1的个数,那么N就被称为 "round number" 。例如,整数9,二进制表示是1001,1001 有两个‘0‘和两个‘1‘; 因此,9是一个round number。26 的二进制表示是 11010 ; 由于它有2个‘0‘和 3个‘1‘,所以它不是round number。 很明显,奶牛们会花费很大精力去转换进制,从而确定谁是胜者。 Bessie 想要作弊,而且认为只要她能够知道在一个指定区间范围内的"round numbers"个数。 帮助她写一个程序,能够告诉她在一个闭区间中有多少round numbers。区间是 [start, finish],包含这两个数。 (1 <= Start < Finish <= 2,000,000,000)

Input

* Line 1: 两个用空格分开的整数,分别表示Start 和 Finish。

Output

* Line 1: Start..Finish范围内round numbers的个数

Sample Input

2 12

Sample Output

6

题解

其实我真的懒得动写题解。。。

不过这题网上做法千奇百怪。3维~5维DP都有,还有用记忆化搜索的。我实在看不下去了。这题其实两维DP+几个循环就足够了!

就是个恶心版数位DP!!!

我们设dp[i][j]为转成二进制后 前导可以为0 长度为i的串,其中零的个数为j的二进制串总个数。

很显然得到状态转移方程:dp[i][j]=dp[i-1][j]+dp[i-1][j-1]

dp数组可以预处理得到。。。

sum(i,j)函数可以累计DP数组求出长度为i且零比一至少多j个的二进制串总个数

那么如何计算ST-ED范围内的答案?

用1...ED的答案减去1...ST-1的答案即可。(solve函数传入x即求1...二进制_x的答案)

比如计算1..110100的答案:

其中几部分是1-1,10-11,100-111,...,10000-11111

最后一部分是求100000-110100的答案

可以拆成100000-101111和110000-110011分别求解,这样就很好解决了,怎么求解还是很明显的。

由此可见求100000-110100的答案之类最后一部分的基本思想是:

从左往右扫到第i位时 当前1比0多d个 如果是此位为0跳过 如果是1则累计ans+=sum(i-1,d-1)。

大体上就是这样,不过细节恶心!

首先,若读入的数为0直接跳过,不然会无限RE。。。

其次,若读入的数转成二进制,0的个数>=1的个数则最后ans++,说明这个数本身合法。

另外还有一些起始点,边界等细节问题。

下面给出参考代码:(其实还是很短的2333)

#include<bits/stdc++.h>
using namespace std;

int n,m;
int dp[35][35];

int sum(int l,int x)
{
	int s=0;
	for(int i=0;i<=l;i++)if(2*i>=l+x)s+=dp[l][i];
	return s;
}

int solve(int x)
{
	int len=0,ans=0,d=1,t=x,v[35];
	while(t)
	{
		v[++len]=t&1;
		t>>=1;
	}
	for(int i=1;i<len;i++)ans+=sum(i-1,1);
	len--;
	while(len)
	{
		if(v[len])ans+=sum(len-1,d-1),d++; else d--;
		len--;
	}
	if(d<=0)ans++;
	return ans;
}

int main()
{
	for(int i=1;i<=32;i++){dp[i-1][0]=1;for(int j=1;j<=i;j++)dp[i][j]+=dp[i-1][j]+dp[i-1][j-1];}
	scanf("%d%d",&n,&m);
	if(n>2)printf("%d\n",solve(m)-solve(n-1)); else printf("%d\n",solve(m));
	return 0;
}

  

时间: 2024-10-19 03:09:29

BZOJ 1662: [Usaco2006 Nov]Round Numbers 圆环数(数位DP+恶心细节)的相关文章

【BZOJ1662】[Usaco2006 Nov]Round Numbers 圆环数 数位DP

[BZOJ1662][Usaco2006 Nov]Round Numbers 圆环数 Description 正如你所知,奶牛们没有手指以至于不能玩"石头剪刀布"来任意地决定例如谁先挤奶的顺序.她们甚至也不能通过仍硬币的方式. 所以她们通过"round number"竞赛的方式.第一头牛选取一个整数,小于20亿.第二头牛也这样选取一个整数.如果这两个数都是 "round numbers",那么第一头牛获胜,否则第二头牛获胜. 如果一个正整数N的二

【分块打表】bzoj1662 [Usaco2006 Nov]Round Numbers 圆环数

#include<cstdio> using namespace std; #define BN 380000 const int table[]={0,185815,378154,561654,744350,886427,1075474,1310828,1513089,1705514,1867434,1971454,2248548,2469454,2649024,2835571,2981002,3136779,3301075,3435869,3558911,3662068,3715857,4

BZOJ1662: [Usaco2006 Nov]Round Numbers

1662: [Usaco2006 Nov]Round Numbers Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 147  Solved: 84[Submit][Status][Discuss] Description 正如你所知,奶牛们没有手指以至于不能玩“石头剪刀布”来任意地决定例如 谁先挤奶的顺序.她们甚至也不能通过仍硬币的方式. 所以她们通过"round number"竞赛的方式.第一头牛选取一个整数,小于20亿. 第二头牛也这样

poj3252Round Numbers非递归数位dp解

Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9894   Accepted: 3569 Description The cows, as you know, have no fingers or thumbs and thus are unable to play Scissors, Paper, Stone' (also known as 'Rock, Paper, Scissors', 'Ro, Sham, Bo'

hdu 4722 Good Numbers(初涉数位dp)

http://acm.hdu.edu.cn/showproblem.php?pid=4722 大致题意:若一个整数的各位数字之和是10的倍数,称这个数为"good number".给出区间[A,B],求出该区间内"good number"的数的个数. 第一道数位dp,折腾了半天才明白怎么回事. 设dp[site][mod]表示到第site位(由高位向低位)前面各位数字之和对10取余为mod的数的个数,进行记忆化搜索.有两个很重要的点,首先是变量up,表示是否到达边界

uestc250windy数数位dp

#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <

USETC 250 windy数 数位DP

注意处理数字只有一位的情况(其实不用怎么处理)= = 简单数位DP #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #

[bzoj1006][SCOI2009]windy数 (数位dp)

Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? Input 包含两个整数,A B. Output 一个整数. Sample Input [输入样例一] 1 10 [输入样例二] 25 50 Sample Output [输出样例一] 9 [输出样例二] 20 HINT [数据规模和约定] 100%的数据,满足 1 <= A <= B <= 2

SPOJ BALNUM Balanced Numbers 状压+数位DP

一开始想了一个用二进制状压的方法,发现空间需要的太大,光光memset都要超时 = = 其实不用每次都memset 也可以用三进制,一开始直接打表出所有的状态转移就好 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream&g