hdu2204(容斥原理)

容斥原理:
A i A_i Ai为集合, ∣ A i ∣ |A_i| Ai为集合大小
∣ A 1 ∪ A 2 ∪ A 3 ∪ A 4 ⋯ A n ∣ |A_1\cup A_2\cup A_3\cup A_4\cdots A_n| A1A2A3A4An
= ∑ i = 1 n ∣ A i ∣ − ∑ i = 1 n ∑ j = i + 1 n ∣ A i ∩ A j ∣ + ∑ i = 1 n ∑ j = i + 1 n ∑ k = j + 1 n ∣ A i ∩ A j ∩ A k ∣ − ⋯ =\sum\limits_{i=1}^{n}|A_i|-\sum\limits_{i=1}^{n}\sum\limits_{j=i+1}^{n}|A_i\cap A_j|+\sum\limits_{i=1}^{n}\sum\limits_{j=i+1}^{n}\sum\limits_{k=j+1}^{n}|A_i\cap A_j\cap A_k|-\cdots =i=1nAii=1nj=i+1nAiAj+i=1nj=i+1nk=j+1nAiAjAk

= ( − 1 ) k + 1 ∑ 1 < = i 1 < i 2 < i 3 < ⋯ < i k < = n ∣ A i 1 ∩ A i 2 ∩ A i 3 ⋯ ∩ A i k ∣ =(-1)^{k+1}\sum\limits_{1<=i_1=(1)k+11<=i1<i2<i3<<ik<=nAi1Ai2Ai3Aik

本题就是一个容斥原理的应用。
∣ A i ∣ |A_i| Ai= ⌊ n n 1 i ⌋ ⌊\frac{n}{n^{\frac{1}{i}}}⌋ ni1n
A i A_i Ai代表 n n n以内的数(如 m m m)满足是 m m m= M i M^i Mi为了减少情况,我们不从 1 1 1开始,从 2 2 2开始,即 ∣ A i ∣ |A_i| Ai记录的是 2 ⋯ n 2\cdots n 2n满足的情况,因为 1 1 1的任意次方都为 1 1 1
则交集如 ∣ A i ∩ A j ∩ A k ∣ |A_i\cap A_j\cap A_k| AiAjAk= ⌊ n n 1 l c m ( i , j , k ) ⌋ ⌊\frac{n}{n^{\frac{1}{lcm(i,j,k)}}}⌋ nlcm(i,j,k)1n;
p o w pow pow函数会有精度损失,开根后需要加一判断是否满足条件,不过这题水了,精度损失倒是对这没有影响,也能AC
然后就是代公式进去就行.

#include
#define ll long long
#define endl '\n'
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
const int MX=1e5+7;
const ll mod=1e18+7;
const double isps=1e-8;
int pri[MX],isp[MX];
using namespace std;
ll qpow(ll a,ll b,ll MOD=mod){for(ll ans=1;;a=a*a,b>>=1){if(b&1)ans=ans*a;if(!b)return ans;}}
ll inv(ll a,ll MOD=mod){return qpow(a,MOD-2,MOD);}
ll __gcm(ll a,ll b){return a*b/__gcd(a,b);}
int mp[MX];
int g[MX];
int top=0;
void prime(){for(int i=2;i<MX;i++){if(!isp[i]){pri[++top]=i;mp[i]=1;}for(int j=1;j<=top&&pri[j]*i<MX;j++){isp[i*pri[j]]=1;if(i%pri[j]==0)break;}}}
ll ant[MX],n;
void dfs(int tmp,int temp,int gcm,int mx,ll&sum,int q)
{
    if(tmp==temp){
        sum+=ant[gcm];
        return ;

    }
    for(int i=q;i<=mx;i++)
    {
         int  gcms=__gcm(gcm,i);
         if(gcms<=mx)
         {
             dfs(tmp+1,temp,gcms,mx,sum,i+1);
         }
    }

}
int main()
{
  ios::sync_with_stdio(0),cin.tie(0);
  while(cin>>n)
  {
      int mx=0;
      ll gt=2;
      while(gt<=n)
      {
          mx++;
          gt*=2;
      }
      ll sum=sqrt(n);
      ll m=sum;
      int a=1;
      a++;
      ant[a]=sum;
      double ans;
      while(a+1<=mx)
      {
          m=pow(n,1.0/(++a));
          ant[a]=m-1;
          sum+=m-1;
          ll gs=m+1;
          int temp=0;
          for(int i=2;i<=a;i++)
          {
              if(1.0*n/(m+1)-gs>isps)
              gs=gs*(m+1);
              else {
                temp=1;
              }
          }
            if(!temp)
          {
              sum++;
              m++;
              ant[a]++;
          }
        }
      for(int i=2;i<=a;i++)
      {
          ll res=0;
          dfs(0,i,1,a,res,2);
          if(i%2)sum+=res;
          else sum-=res;
      }

      cout<<sum<<endl;
  }
}

你可能感兴趣的:(数学)