HDU6053(72/600)

本文介绍了一道使用莫比乌斯反演解决的算法题,题目要求计算满足特定条件的不同数组数量。通过实现代码详细展示了如何运用莫比乌斯函数及反演技巧来求解此类问题。

Problem Description
You are given an array A , and Zhu wants to know there are how many different array B satisfy the following conditions?

  • 1≤Bi≤Ai
  • For each pair( l , r ) (1≤l≤r≤n) , gcd(bl,bl+1…br)≥2

Input
The first line is an integer T(1≤T≤10) describe the number of test cases.

Each test case begins with an integer number n describe the size of array A.

Then a line contains n numbers describe each element of A

You can assume that 1≤n,Ai≤105

Output
For the kth test case , first output “Case #k: ” , then output an integer as answer in a single line . because the answer may be large , so you are only need to output answer mod 109+7

Sample Input
1
4
4 4 4 4

Sample Output
Case #1: 17

Source
2017 Multi-University Training Contest - Team 2

Recommend
liuyiding | We have carefully selected several similar problems for you: 6055 6054 6053 6052 6051

莫比乌斯反演的第一次用….
其实就是说莫比乌斯反演那个公式可以反过来用….
用大的算小的…

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=200105;
int normal[maxn];
int mu[maxn];
int prime[maxn];
int pcnt,u=0;
void Init()
{
    memset(normal,0,sizeof(normal));
    mu[1] = 1;
    pcnt = 0;
    for(int i=2; i<maxn; i++)
    {
        if(!normal[i])
        {
            prime[pcnt++] = i;
            mu[i] = -1;
        }
        for(int j=0; j<pcnt&&i*prime[j]<maxn; j++)
        {
            normal[i*prime[j]] = 1;
            if(i%prime[j]) mu[i*prime[j]] = -mu[i];
            else
            {
                mu[i*prime[j]] = 0;
                break;
            }
        }
    }
}
int tu[maxn],sum[maxn],n,q;
ll mo=1e9+7;
ll ksm(ll ds,ll zs)
{
    ll fs=1;
    while(zs)
    {
        if(zs&1)fs*=ds;

        fs%=mo;
        ds*=ds;
        ds+=mo;
        ds%=mo;
        zs>>=1; //cout<<zs<<endl;
    }
    return (fs+mo)%mo;
}
ll f[maxn],F[maxn];
int main()
{
    Init();
//  cout<<ksm(2,2)<<endl;
//  return 0;
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n;
        memset(f,0,sizeof(f));
        memset(F,0,sizeof(F));
        memset(tu,0,sizeof(tu));
        memset(sum,0,sizeof(sum));
        int shang=0,xia=1e9;
        for(int a=1;a<=n;a++)
        {
            scanf("%d",&q);
            tu[q]++;
            shang=max(shang,q);
            xia=min(xia,q);
        }
        for(int a=1;a<=200010;a++)
        {
            sum[a]=sum[a-1]+tu[a];
        }
        for(int a=2;a<=xia;a++)
        {
            F[a]=1;
            for(int b=a;b<=shang;b+=a)
            {
                int qj=b/a;
        //      int y=min(,shang);
            //  cout<<"ccccc";
    //      cout<<sum[y]-sum[b-1]<<endl<<qj<<endl;
                F[a]=(F[a]*ksm(qj,sum[b+a-1]-sum[b-1])%mo+mo)%mo;
            }//cout<<"asd";
        }
    //  return 0;
        for(int a=2;a<=xia;a++)
        {
            for(int b=1;;b++)
            {
                if(b*a>xia)break;
                f[a]=(f[a]+mu[b]*F[a*b]+mo)%mo;
            }
        }

        ll dan=0;
        for(int a=2;a<=xia;a++)
        {
            dan=(dan+f[a]+mo)%mo;
        }
        printf("Case #%d: %lld\n",++u,dan%mo);
    }
}
基于模拟退火的计算器 在线运行 访问run.bcjh.xyz。 先展示下效果 https://pan.quark.cn/s/cc95c98c3760 参见此仓库。 使用方法(本地安装包) 前往Releases · hjenryin/BCJH-Metropolis下载最新 ,解压后输入游戏内校验码即可使用。 配置厨具 已在2.0.0弃用。 直接使用白菜菊花代码,保留高级厨具,新手池厨具可变。 更改迭代次数 如有需要,可以更改 中39行的数字来设置迭代次数。 本地编译 如果在windows平台,需要使用MSBuild编译,并将 改为ANSI编码。 如有条件,强烈建议这种本地运行(运行可加速、可多次重复)。 在 下运行 ,是游戏中的白菜菊花校验码。 编译、运行: - 在根目录新建 文件夹并 至build - - 使用 (linux)(windows) 运行。 最后在命令行就可以得到输出结果了! (注意顺序)(得到厨师-技法,表示对应新手池厨具) 注:linux下不支持多任务选择 云端编译已在2.0.0弃用。 局限性 已知的问题: - 无法得到最优解! 只能得到一个比较好的解,有助于开阔思路。 - 无法选择菜品数量(默认拉满)。 可能有一定门槛。 (这可能有助于防止这类辅助工具的滥用导致分数膨胀? )(你问我为什么不用其他语言写? python一个晚上就写好了,结果因为有涉及json读写很多类型没法推断,jit用不了,算这个太慢了,所以就用c++写了) 工作原理 采用两层模拟退火来最大化总能量。 第一层为三个厨师,其能量用第二层模拟退火来估计。 也就是说,这套方法理论上也能算厨神(只要能够在非常快的时间内,算出一个厨神面板的得分),但是加上厨神的食材限制工作量有点大……以后再说吧。 (...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值