Contest2257 - 抗击疫情,从我做起--大中小学生联合训练赛第五十二场

问题 E: 喜爱

  • 题目描述

  • 小s最近对数字情有独钟。他又发现了一种神奇的数字。对于数x,如果它二进制表示中只有一位是0,则x就会被小s所喜爱。比如5,二进制为101,则它被小s所喜爱。
    现在,小s想知道,对于一个区间[L,R],有多少数是他所喜爱的。

  • 输入

    输入包含多组数据。
    输入第一行T,表示数据组数。
    每组数组仅有一行,包含两个正整数[L,R]。

  • 输出

    对于每组数据输出一行,表示答案。

  • 样例输入 Copy

    2
    5 10
    2015 2015

  • 样例输出 Copy

    2
    1

  • 提示

    对于30%的数据:L,R≤106,T≤10
    对于60%的数据:L,R≤1010,T≤100
    对于100%的数据:L,R≤1018,T≤10000


  • 题意分析 就是要求出一个区间内二进制表示情况下只含一个0的个数;
  • 思路分析 : 先说明一个最最最重要的: 左移右移无法让数字达到1e10以上就这个地方凉凉了好久;
  • 就下来是我的思路:
    1 : 首先打表是必不可少的,要不你每次都要运行肯定不行;我是按2进制位数打的表这样我感觉简单点,(简单就是一下 怎么打的表:如果2进制有x位 会有x-1个可行的值,所以就可以了);
    2 : 因为由于左右两个界限你可以先从右界限开始看:找到他二进制位数的下一位,(这样才会比这个数值大),用快速幂表示出来(我一开始用的左移,不行);然后让这个数-1,(目的是让其二进制位全部为1)这样只要分别减去2i判断与右端点的大小既可以了判断这个是否符合题意了;
    3:2一样判断左界限,不过这时是大于等于左界限符合条件
    4: 因为两端的已经求出来了,直接用我们打好的表来表示中间的那部分,即a[右端点二进制位]-a[左端点二进制位+1];
    这样就是所求,别忘了每次初始化呦。

里面的注释代表我修改过的痕迹,呜呜呜~~~~

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef unsigned long long ll;
using namespace std;
const int maxn=210;
#define inf 0x3f3f3f3f
const int mod=998244353;
const int MOD=10007;

ll  n,m,k,sum,cnt;
ll a[maxn],b[maxn],dp[maxn];
char str[maxn],s[maxn];

ll qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)
		{
			ans=(ans*a);
		}
		a=(a*a);
		b/=2;
	}
	return ans;
} 

int main(){
	ll t;
	cin>>t;
	a[0]=1;
	for(ll i=1;i<=200;i++)
		a[i]=a[i-1]+i-1;
//	for(ll i=1;i<=200;i++)		cout<<a[i]<<" ";
	while(t--){
	cin>>n>>m;
	sum=0;
	for(int i=0;i<=200;i++)
		if(m<qpow(2,i))
		{
			k=i;
	//		cout<<i<<endl;
			break;
		}
	ll x=qpow(2,k)-1;//quan 1
//	cout<<x<<endl;
	for(int i=k-2;i>=0;i--)
		{
			if(m>=(x-qpow(2,i)))
			{
				sum++;
	//			cout<<x-(1<<i)<<endl;
				}
		}
		
	for(int i=1;i<=200;i++)
		if(n<qpow(2,i))
		{
			cnt=i;
		//	cout<<i<<endl;
			break;
		}
	ll y=qpow(2,cnt)-1;
	
	for(int i=0;i<cnt-1;i++)
		if(n<=(y-qpow(2,i))){
		 sum++;
		}
//	cout<<a[k-1]<<" "<<a[cnt]<<endl;
	//cout<<sum<<endl;
	sum+=a[k-1]-a[cnt];
	cout<<sum<<endl;
	}
	return 0;
} 



问题 I: Mysterious Light

Snuke is conducting an optical experiment using mirrors and his new invention, the rifle of Mysterious Light.

Three mirrors of length N are set so that they form an equilateral triangle. Let the vertices of the triangle be a,b and c.

Inside the triangle, the rifle is placed at the point p on segment ab such that ap=X. (The size of the rifle is negligible.) Now, the rifle is about to fire a ray of Mysterious Light in the direction of bc.

The ray of Mysterious Light will travel in a straight line, and will be reflected by mirrors, in the same ways as “ordinary” light. There is one major difference, though: it will be also reflected by its own trajectory as if it is a mirror! When the ray comes back to the rifle, the ray will be absorbed.
在这里插入图片描述

The following image shows the ray’s trajectory where N=5 and X=2.

It can be shown that the ray eventually comes back to the rifle and is absorbed, regardless of the values of N and X. Find the total length of the ray’s trajectory.

Constraints
2≦N≦1012
1≦X≦N−1
N and X are integers.
Partial Points
300 points will be awarded for passing the test set satisfying N≦1000.
Another 200 points will be awarded for passing the test set without additional constraints.

输入

The input is given from Standard Input in the following format:N X

输出

Print the total length of the ray’s trajectory.

样例输入 Copy

5 2

样例输出 Copy

12

提示

Refer to the image in the Problem Statement section. The total length of the trajectory is 2+3+2+2+1+1+1=12.
思路:就是列出来一部分 找出规律。
代码:

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=210;
#define inf 0x3f3f3f3f
const int mod=998244353;
const int MOD=10007;
 
ll  n,m,k,sum,cnt;
ll a[maxn],b[maxn],dp[maxn];
char str[maxn],s[maxn];
 
ll gcd(ll a,ll b){
    while(b){
        ll temp=a%b;
        a=b;
        b=temp;
    }
    return a;
}
int main(){
    ll x;
    cin>>n>>x;
    cout<<(n-gcd(n,x))*3<<endl;
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值