开心数

题目地址
2021-04-03 22:40:34 星期六

这题的数据范围时l,r <= 10^18所以简单的模拟是不能ac的,时间主要花费在每个数都要求一遍二进制来判断是否只有一个0位,所以可以预先处理出所有开心数,遍历真个开心数来判断是否在l,r这个区间范围内即可,那么整个问题变成如何预处理出开心数。

找出所有在二进制表示的情况下,所有位数都为1的数。然后拿这些数分别减2的次幂(其指数比该数的>找出所有在二进制表示的情况下,所有位数都为1的数。然后拿这些数分别减2的次幂(其指数比该数的 最高位数低)的所有情况,一 一列举

code

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll; // 10^18要开long long
ll log2_[61]={1}; // 存2的n次幂 例如2 4 8 16...2^61
ll m[2000]; //存储开心数
int cnt=1; // 开心数数组的下标
void init()
{
    for(int i=1;i<61;i++) //求2的n次幂 初始化首元素为1
        log2_[i]=log2_[i-1]*2;
    for(int i=2;i<61;i++)
    {
        for(int j=i-2;j>=0;j--)
        {
            m[cnt++]=log2_[i]-1-log2_[j];
			//  log2_[i]-1 求出所有位数为1的数
			// 111-(10)=101 即可求出一个开心数
        }
    }
}
int main()
{
    init();
    int t;
    cin>>t;
    
    while(t--)
    {
        ll l,r;
        cin>>l>>r;
        int res=0;
        int pos=0;
        for(int i=1;i<=cnt;i++)
        {
            if(m[i]<=r&&m[i]>=l)res++;
            if(m[i]>r)break;
        }
        cout<<res<<endl;
    }
    return 0;
}

开心整数

题目地址

需要注意0!=1

code

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1000010;
bool st[N];
long long a[15];
// 
void dfs(int n,int p)//n为题目输入的数,p为某个数的阶乘
{
    if(p==-1)return;
    st[n+a[p]]=1;
    dfs(n+a[p],p-1);//加上当前的数的阶乘
    dfs(n,p-1);//不加当前数的阶乘
}
int main()
{
    int n;
    a[0]=a[1]=1;
    for(int i=2;i<10;i++) // 处理0-9的阶乘
        a[i]=a[i-1]*i;
    dfs(0,9);
    while(scanf("%d",&n),n>=0)
    {
        if(st[n])
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

以失败告终!