• [牛客练习赛29D]禁止动规


    description

    newcoder
    你在一个无限长的数轴上,一开始你在原点
    本来你只有两种操作:向左dp,以及向右dp
    然而由于禁止dp
    于是你只能另寻出路
    万幸的是,dp之神随机给了你n个变量,既(x_1,x_2, ... , x_n),每个变量的值在([1,m])之间,且是整数
    每次你可以选择一个变量(x_i),然后向左走(x_i)个单位,或者向右走(x_i)个单位
    问走到原点右侧1单位距离的概率是多大?
    既随机给定n个变量后,存在至少一种从数轴上的0点走到1点的方案的概率
    设答案为(w),那么你只需要输出(w imes m^n)在模(2^{64})意义下的值
    注意:

    1. 一个变量可以选多次,也可以不选
    2. 可以走到负半轴

    data range

    [n,mle 10^{11} ]

    solution

    终于学会杜教筛.jpg

    我们知道合法方案一定存在两个数(x_j,x_k)互质。

    考虑容斥减掉(x_i)全部为(k)的倍数的方案,那么答案即为

    [sum_{i=1}^{m}mu(i)(lfloorfrac{m}{i} floor)^n ]

    数论分块+杜教筛求(mu(i))的前缀和即可。

    时间复杂度为(O(n^{frac{2}{3}}))

    Code

    #include<bits/stdc++.h>
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<iomanip>
    #include<cstring>
    #include<complex>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cassert>
    #include<ctime>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    #define F "a"
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define RG register
    using namespace std;
    typedef unsigned long long ll;
    typedef pair<int,int> PI;
    typedef vector<int>VI;
    //typedef long long ll;
    typedef long double dd;
    const dd eps=1e-6;
    const int mod=1e4;
    const int N=2e7+10;
    const dd pi=acos(-1);
    const int inf=2147483647;
    const ll INF=1e18+1;
    const ll P=100000;
    inline ll read(){
      RG ll data=0,w=1;RG char ch=getchar();
      while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
      if(ch=='-')w=-1,ch=getchar();
      while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
      return data*w;
    }
    
    inline void file(){
      srand(time(NULL)+rand());
      freopen(F".in","r",stdin);
      freopen(F".out","w",stdout);
    }
    
    int pri[N],mu[N];bool vis[N];
    inline void sieve(){
      vis[1]=mu[1]=1;
      for(RG int i=2;i<N;i++){
        if(!vis[i])pri[++pri[0]]=i,mu[i]=-1;
        for(RG int j=1;j<=pri[0]&&1ll*i*pri[j]<N;j++){
          vis[i*pri[j]]=1;mu[i*pri[j]]=mu[i]*mu[pri[j]];
          if(i%pri[j]==0){mu[i*pri[j]]=0;break;}
        }
      }
      for(RG int i=2;i<N;i++)mu[i]+=mu[i-1];
    }
    inline ll poww(ll a,ll b){
      RG ll ret=1;
      for(;b;b>>=1,a=a*a)
        if(b&1)ret=ret*a;
      return ret;
    }
    ll n,m,ans;
    map<ll,ll>premu;
    ll getmu(ll n){
      if(n<N)return mu[n];
      if(premu.find(n)!=premu.end())return premu[n];
      ll &res=premu[n];res=1;
      for(RG ll i=2,j;i<=n;i=j+1)j=n/(n/i),res-=getmu(n/i)*(j-i+1);
      return res;
    }
    
    int main()
    {
      n=read();m=read();sieve();
      for(RG ll i=1,j;i<=m;i=j+1)
        j=m/(m/i),ans+=(getmu(j)-getmu(i-1))*poww(m/i,n);
      printf("%llu
    ",ans);return 0;
    }
    
    
  • 相关阅读:
    网游内存数据库的设计(1)
    基于用户级线程的远程调用效率测试
    实现c协程
    KendyNet for linux
    开源一个lua的网络库
    C语言重写网络发送/接收封包
    C协程使用举例
    各种内存分配器的对比测试
    KendyNet性能测试
    C协程实现的效率对比
  • 原文地址:https://www.cnblogs.com/cjfdf/p/9819714.html
Copyright © 2020-2023  润新知