幸运数字(容斥原理+高精度与低精度的加 减 除)

8 篇文章 0 订阅
1 篇文章 0 订阅

幸运数字

题目描述:
LYK 最近运气很差,例如在 NOIP 初赛中仅仅考了 90 分,刚刚卡进复赛,于是它决定使用一些方法来增加自己的运气值。
它觉得,通过收集幸运数字可以快速的增加它的 RP 值。
它给幸运数字下了一个定义:如果一个数 x 能被 3 整除或被 5 整除或被 7 整除,则这个数为幸运数字。
于是它想让你帮帮它在 L~R 中存在多少幸运数字。
输入格式:
第一行两个数 L,R。
输出格式:
一个数表示答案。
输入样例
10 15
输出样例
4
数据范围:
对于 50%的数据 1<=L<=R<=10^5。
对于 60%的数据 1<=L<=R<=10^9。
对于 80%的数据 1<=L<=R<=10^18。
对于 90%的数据 1<=L<=R<=10^100。
对于另外 10%的数据 L=1, 1<=R<=10^100。
对于 100%的数据 L, R 没有前导 0。
思路:
容斥原理
设num(n,i)表示1~n中是i的倍数
则求1~n中3或5或7的倍数为
num(n,3)+num(n,5)+num(n,7)-num(n,3*5)-num(n,3*7)-num(5*7)+num(n,3*5*7)
这样求出1~r的减去1~l-1的即可
高精度!!!

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1010;
int len,a[maxn],b[maxn],t[maxn],ans[maxn];
int sa[maxn],sb[maxn],c[2]={1,1};
char s1[maxn],s2[maxn];
void jian2(int *a,int *b)
{
    memset(sa,0,sizeof(sa));
    memset(sb,0,sizeof(sb));
    sa[0]=a[0];
    for(int i=1;i<=a[0];i++)
    sa[i]=a[a[0]-i+1];
    for(int i=1;i<=b[0];i++)
    sb[i]=b[b[0]-i+1];
    int len=1;
    while(len<=sa[0])
    {
        sa[len]=sa[len]-sb[len];
        if(sa[len]<0)
        {
            sa[len]=sa[len]+10;
            sa[len+1]--;
        }
        len++;
    }
    while(sa[0]>1&&!sa[a[0]])
    sa[0]--;a[0]=sa[0];
    for(int i=1;i<=sa[0];i++)
    a[i]=sa[sa[0]-i+1];
}
void div(int *r,int *a,int x)
{
    int s=0;r[0]=a[0];
    for(int i=1;i<=a[0];i++)
    {
        s=s*10+a[i];
        r[i]=s/x;
        s=s%x;
    }
}
void add(int *a,int *b)
{
    memset(sa,0,sizeof(sa));
    memset(sb,0,sizeof(sb));
    int len1=a[0],len2=b[0],len=1;
    for(int i=1;i<=len2;i++)
    sb[i]=b[len2-i+1];
    while(len<=len1||len<=len2)
    {
        sa[len]+=a[len]+sb[len];
        sa[len+1]=sa[len]/10;
        sa[len]=sa[len]%10;
        len++;
    }
    while(len>1&&!sa[len])
    len--;sa[0]=len;
    for(int i=0;i<=sa[0];i++) a[i]=sa[i];
}
void jian(int *a,int *b)
{
    memset(sb,0,sizeof(sb));
    for(int i=1;i<=b[0];i++)
    sb[i]=b[b[0]-i+1];
    int len=1;
    while(len<=a[0])
    {
        a[len]=a[len]-sb[len];
        if(a[len]<0)
        {
            a[len]=a[len]+10;
            a[len+1]--;
        }
        len++;
    }
    while(a[0]>1&&!a[a[0]])
    a[0]--;
}
int main()
{
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    cin>>s1>>s2;
    int l1=strlen(s1),l2=strlen(s2);
    a[0]=l1,b[0]=l2;
    for(int i=1;i<=l1;i++) a[i]=s1[i-1]-'0'; 
    for(int i=1;i<=l2;i++) b[i]=s2[i-1]-'0';
    jian2(a,c);
    div(t,b,3);add(ans,t);
    div(t,b,5);add(ans,t);
    div(t,b,7);add(ans,t);
    div(t,a,3*5);add(ans,t);
    div(t,a,3*7);add(ans,t);
    div(t,a,5*7);add(ans,t);
    div(t,b,3*5*7);add(ans,t);
    div(t,b,3*5);jian(ans,t);
    div(t,b,3*7);jian(ans,t);
    div(t,b,5*7);jian(ans,t);
    div(t,a,3);jian(ans,t);
    div(t,a,5);jian(ans,t);
    div(t,a,7);jian(ans,t);
    div(t,a,3*5*7);jian(ans,t);
    for(int i=ans[0];i>=1;i--)
    cout<<ans[i];
    fclose(stdin);fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值