【题解】Round Numbers

29 篇文章 0 订阅
6 篇文章 0 订阅

Round Numbers

Description

    你知道的牛没有手指或拇指,因此无法玩石头剪刀布,以便做出任意决定,比如谁首先被挤奶。他们甚至不能翻转硬币,因为很难用蹄子折腾。

    因此,他们采取了"Round Numbers"配对。第一只牛选择一个小于20亿的整数,第二只牛做同样的事情。如果数字都是“Round Number”,那么第一头牛就会赢,

否则第二头牛胜。

如果N的二进制表示中0的个数大于或等于1的个数,则正整数N被称为“Round Number”。例如,当以二进制形式写入时,整数9是1001,1001有两个0和两个1;因此,9是一个"Round Number"。整数26是二进制的11010;由于它有两个0和三个1,它不是一个"Round Number"。

显然,奶牛需要一段时间才能将数字转换为二进制,所以获胜者需要一段时间才能确定。Bessie想要作弊,如果她知道在一定范围内有多少“Round Number”,她就可以作弊。

帮助她编写一个程序,告诉输入中给出的包含范围内有多少个“Round Number”(1≤Start≤Finish≤2,000,000,000)。


(原文:

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', and a host of other names) in order to make arbitrary decisions such as who gets to be milked first. They can't even flip a coin because it's so hard to toss using hooves.

They have thus resorted to "round number" matching. The first cow picks an integer less than two billion. The second cow does the same. If the numbers are both "round numbers", the first cow wins,
otherwise the second cow wins.

A positive integer N is said to be a "round number" if the binary representation ofN has as many or more zeroes than it has ones. For example, the integer 9, when written in binary form, is 1001. 1001 has two zeroes and two ones; thus, 9 is a round number. The integer 26 is 11010 in binary; since it has two zeroes and three ones, it is not a round number.

Obviously, it takes cows a while to convert numbers to binary, so the winner takes a while to determine. Bessie wants to cheat and thinks she can do that if she knows how many "round numbers" are in a given range.

Help her by writing a program that tells how many round numbers appear in the inclusive range given by the input (1 ≤Start < Finish ≤ 2,000,000,000).)


Input

1行:两个空格分隔的整数,分别为Start和Finish。


Output

1行:一个整数,它是范围Start..Finish中的"Round Number"的个数


Sample Input

2 12


Sample Output

6


又是一道数位dp的题目。。。

记忆化搜索,以f[a][b][c]记录剩下a位二进制位并且已有b个0,c个1的“Round Number”个数。

搜索过程 dfs(len,c0,c1,full,up0) 中:

len代表还剩下的二进制位的长度,

c0,c1分别代表已有的0和1的数目,

up0代表是否还在前导零中(前导零的数目不计入零的数目中)。

代码:

#include <cstdio>

#define ll long long

ll f[35][35][35];
int num[35];

ll dfs(int len,int c0,int c1,bool full,bool up0)
{
	if(!len)
		if(up0 || c0>=c1)return 1; else return 0;
	if(!up0 && !full && f[len][c0][c1])return f[len][c0][c1];
	ll sum=0;
	for(int i=0;i<=(full?num[len]:1);++i)
		if(up0&&!i)sum+=dfs(len-1,0,0,full&&i==num[len],1);
		else
			if(i)sum+=dfs(len-1,c0,c1+1,full,0); else sum+=dfs(len-1,c0+1,c1,full&&i==num[len],0);
	if(!up0 && !full)f[len][c0][c1]=sum;
	return sum;
}

ll work(ll x) 
{
	num[0]=0;
	while(x)
	{
		num[++num[0]]=x&1;
		x>>=1;
	}
	return dfs(num[0],0,0,1,1);
}

int main()
{
	ll a,b;
	while(~scanf("%lld%lld",&a,&b))printf("%lld",work(b)-work(a-1));
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
06-01
这道题是一道典型的费用限制最短路题目,可以使用 Dijkstra 算法或者 SPFA 算法来解决。 具体思路如下: 1. 首先,我们需要读入输入数据。输入数据中包含了道路的数量、起点和终点,以及每条道路的起点、终点、长度和限制费用。 2. 接着,我们需要使用邻接表或邻接矩阵来存储图的信息。对于每条道路,我们可以将其起点和终点作为一个有向边的起点和终点,长度作为边权,限制费用作为边权的上界。 3. 然后,我们可以使用 Dijkstra 算法或 SPFA 算法求解从起点到终点的最短路径。在这个过程中,我们需要记录到每个点的最小费用和最小长度,以及更新每条边的最小费用和最小长度。 4. 最后,我们输出从起点到终点的最短路径长度即可。 需要注意的是,在使用 Dijkstra 算法或 SPFA 算法时,需要对每个点的最小费用和最小长度进行松弛操作。具体来说,当我们从一个点 u 经过一条边 (u,v) 到达另一个点 v 时,如果新的费用和长度比原来的小,则需要更新到达 v 的最小费用和最小长度,并将 v 加入到优先队列(Dijkstra 算法)或队列(SPFA 算法)中。 此外,还需要注意处理边权为 0 或负数的情况,以及处理无法到达终点的情况。 代码实现可以参考以下样例代码: ```c++ #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; const int MAXN = 1005, MAXM = 20005, INF = 0x3f3f3f3f; int n, m, s, t, cnt; int head[MAXN], dis[MAXN], vis[MAXN]; struct Edge { int v, w, c, nxt; } e[MAXM]; void addEdge(int u, int v, int w, int c) { e[++cnt].v = v, e[cnt].w = w, e[cnt].c = c, e[cnt].nxt = head[u], head[u] = cnt; } void dijkstra() { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); dis[s] = 0; q.push(make_pair(0, s)); while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; i != -1; i = e[i].nxt) { int v = e[i].v, w = e[i].w, c = e[i].c; if (dis[u] + w < dis[v] && c >= dis[u] + w) { dis[v] = dis[u] + w; q.push(make_pair(dis[v], v)); } } } } int main() { memset(head, -1, sizeof(head)); scanf("%d %d %d %d", &n, &m, &s, &t); for (int i = 1; i <= m; i++) { int u, v, w, c; scanf("%d %d %d %d", &u, &v, &w, &c); addEdge(u, v, w, c); addEdge(v, u, w, c); } dijkstra(); if (dis[t] == INF) printf("-1\n"); else printf("%d\n", dis[t]); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值