zoukankan      html  css  js  c++  java
  • luogu P6583 回首过去 简单数论变换 简单容斥

    LINK:回首过去

    考试的时候没推出来 原因:状态真的很差 以及 数论方面的 我甚至连除数分块都给忘了.

    手玩几个数据 可以发现 (frac{x}{y})满足题目中的条件当且仅当 这个是一个既约分数 且 y中只含2,5的因子.

    枚举y考虑贡献 先除掉本身的2,5的倍数后变成w1 之后考虑x 1~n中x只要是w1的倍数那么都是不合法的。

    把这些数给去掉即可.这样就得到了一个O(n)的做法。

    观察数据范围 容易想到 考察的是一个根号的算法。

    此时考虑枚举w1 那么可以发现w1要满足 不是2,5的倍数 此时贡献为n/w1 考虑这样的数字有多少个 容易发现可以暴力统计 强行乘上若干个2和若干个5.

    推到这里我昨天卡住了 因为这还没有达到很好的效果 忘了整除分块了 直接分块 容易得到一个(sqrt{n}log_2log_5)的做法。

    不过这样 只能信仰过题。考虑把两个log优化掉 可以发现求多少个的时候其实是求 1~n/w1中 只包含2,5质因子数的个数。

    将这个东西预处理 然后从小到大排序 整除分块的时候 就可以单调的判断了 复杂度(sqrt{n}+log^3)

    中间一个小步骤需要简单容斥一下.

    const ll MAXN=10010;
    ll n,ans,cnt;
    ll a[MAXN];
    inline ll calc(ll x)
    {
    	return x-x/2-x/5+x/10;
    }
    signed main()
    {
    	//freopen("1.in","r",stdin);
    	get(n);
    	for(ll i=1;i<=n;i=i*2)
    		for(ll j=1;i*j<=n;j=j*5)a[++cnt]=i*j;
    	sort(a+1,a+1+cnt);
    	ll w1,w2,flag=cnt;
    	for(ll i=1;i<=n;i=w2+1)
    	{
    		w1=n/i;w2=n/w1;
    		while(a[flag]>w1&&flag)--flag;
    		ans=ans+w1*(calc(w2)-calc(i-1))*flag;
    	}
    	putl(ans);
    	return 0;
    }
    
  • 相关阅读:
    oracle启动的三步
    Solaris下vi的简单使用帮助
    Solaris下ftp配置(初稿待补充)
    soap笔记1
    Solaris 10 查看机器的网卡mac地址
    查看表空间名称与对应文件
    [转]Ubuntu10.04的网络配置
    [转]红帽企业版RHEL6使用Fedora13的yum源
    [转]linux忘记密码怎么办法
    [转]个人管理 - IT人士书籍推荐(已读)
  • 原文地址:https://www.cnblogs.com/chdy/p/13009533.html
Copyright © 2011-2022 走看看