[牛客练习赛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\times m^n\)在模\(2^{64}\)意义下的值
注意:

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

data range

\[n,m\le 10^{11} \]

solution

终于学会杜教筛.jpg

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

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

\[\sum_{i=1}^{m}\mu(i)(\lfloor\frac{m}{i}\rfloor)^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\n",ans);return 0;
}

posted @ 2018-10-19 22:51  cjfdf  阅读(352)  评论(0编辑  收藏  举报