<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      I am a teacher!

      導(dǎo)航

      二進(jìn)制枚舉(二)

             二進(jìn)制枚舉的方法在實際問題中應(yīng)用還是非常方便的。下面繼續(xù)體會這一方法的使用。

             先看如下的問題。

             給出一個數(shù)n(1<=n<=1018),求1到n中,有多少個數(shù)不是2、5、7、11的倍數(shù)?

             問題分析

             如果n的值較小,可以采用一個簡單的一重循環(huán)進(jìn)行處理即可。編寫如下的程序。

      #include <stdio.h>
      int main()
      {
          int n;
          while (scanf("%d",&n)!=EOF)
          {
              int i,cnt=0;
              for (i=1;i<=n;i++)
              {
                 if (i%2!=0 && i%5!=0 && i%7!=0 && i%11!=0)
                    cnt++;
              }
              printf("%d\n",cnt);
          }
          return 0;
      }

             但由于題目中給定n值最大可達(dá)10的18次方,因此采用上面的簡單一重循環(huán)求解,運(yùn)行太耗時。為提高效率,我們可以這樣來解決問題。

             先求出求1到n中有多少個數(shù)(設(shè)為cnt個)是2、5、7或11的倍數(shù)。

             以n=100為例說明。

             2的倍數(shù)有 n/2=100/2=50 個,即{2,4,6,8,10,…,100} 共50個。

             5的倍數(shù)有 n/5=100/5=20 個,即{ 5,10,15,…,100 } 共20個。

             7的倍數(shù)有 n/7=100/7=14 個,即{ 7,14,21,…,98} 共14個。

             11的倍數(shù)有 n/11=100/11=9 個,即{ 11,22,33,…,99 } 共9個。

             若將上面的4個數(shù)相加 cnt=50+20+14+9=93,得出1到20中有93個數(shù)是2、5、7或11的倍數(shù)。這個結(jié)論,肯定是不對的。

             從上面的列舉就可以看出,2×5=10,10的倍數(shù)有{10,20,…,100}這10個數(shù),它們均被計數(shù)了兩次,因此應(yīng)減去 n/(2*5)=100/10=10。

             同理,2×7、2×11、5×7、5×11、7×11這些數(shù)的倍數(shù)均被計算了2次,也應(yīng)減去。

             即 cnt=(n/2+n/5+n/7+n/11) –(n/(2*5)+n/(2*7)+n/(2*11) +n/(5*7) +n/(5*11) +n/(7*11))

             這樣處理后,仍然不對。例如,2×5×7=70這個數(shù),在計數(shù)cnt時,是2的倍數(shù)加1,是5的倍數(shù)加1,是7的倍數(shù)加1,是2×5的倍數(shù)減1,是2×7的倍數(shù)減1,是5×7的倍數(shù)減1。因此,在Cnt計數(shù)中,70這個數(shù)相當(dāng)1次也沒有計數(shù)。因此,應(yīng)加上它。同理,2×5×11、2×7×11、5×7×11這些數(shù)的倍數(shù)個數(shù)也均應(yīng)加上。

             這樣加上后,2×5×7×11=770這個數(shù)的倍數(shù)個數(shù)又被多加了,應(yīng)減去。

             最終,cnt=(n/2+n/5+n/7+n/11)

                               –(n/(2*5)+n/(2*7)+n/(2*11) +n/(5*7) +n/(5*11) +n/(7*11))

                              +(n/(2*5*7)+ n/(2*5*11) + n/(2*7*11) + n/(5*7*11))

                              -( n/(2*5*7*11))

             這就是所謂的容斥原理,簡單說就是奇加偶減

             這樣,n=100時,計算cnt=(100/2+100/5+100/7+100/11)-(100/10+100/14+100/22+100/35+100/55+100/77)+(100/70+100/110+100/154+100/385)-(100/770)

                                                     =(50+20+14+9)-(10+7+4+2+1+1)+(1+0+0+0+0)-0 =69。

             即1到100中有 69 個數(shù)是2、5、7或11的倍數(shù)。有 100-69=31個數(shù)不是2、5、7或11的倍數(shù)。

             而對2、5、7或11這4個數(shù)的各種組合,可以采用4位二進(jìn)制數(shù)枚舉。

             例如,0001表示只選中2,子集為{ 2 };0010表示只選中5,子集為{ 5 };0011表示選中2和5,子集為{ 2,5 };…;1111表示4個元素全部選中,子集為{ 2,5,7,11}。

             對每種組合情況,計算選中的數(shù)的乘積的倍數(shù)的個數(shù),若選中數(shù)的個數(shù)為奇數(shù),則加上倍數(shù)的個數(shù);若選中數(shù)的個數(shù)為偶數(shù),則減去倍數(shù)的個數(shù)。最后,得到的結(jié)果就是所求的答案。

             采用二進(jìn)制枚舉和容斥原理相結(jié)合的方法,編寫如下的程序。

      #include <stdio.h>
      int main()
      {
          int p[4]={2,5,7,11};
          long long n;
          while (scanf("%lld",&n)!=EOF)
          {
              long long  ans=0;
              int i,j;
              for (i=1;i<(1<<4);i++)
              {
                  long long muti=1;
                  int cnt=0;
                  for (j=0;j<4;j++)
                  {
                     if (i&(1<<j))
                     {
                        cnt++;
                        muti*=p[j];
                     }
                  }
                  if(cnt&1)  ans+=n/muti;  // 容斥原理,奇加偶減
                  else       ans-=n/muti;
              }
              printf("%lld\n",n-ans);
          }
          return 0;
      } 

      【例1】可以找到幾個數(shù)

      問題描述

      給出一個整數(shù)N和一個有M個整數(shù)的整數(shù)集,有多少個比N小的整數(shù),它們可以被集合中的任一整數(shù)整除。例如,N=12,M整數(shù)集是{2,3},所以有另一個集合{2,3,4,6,8,9,10},該集合的所有整數(shù)都可以被2或3整除。因此,可知道結(jié)果為7,即有7個數(shù)。

      輸入

      輸入包括多組測試用例。對于每組測試用例,第一行包含兩個整數(shù)N和M。第二行包含M個整數(shù),并且它們都彼此不同。0<N<2^31,0<M<=10,且M個整數(shù)為非負(fù)且不會超過20。

      輸出

      對于每組測試用例,用1行輸出答案。

      輸入樣例

      12 2

      2 3

      輸出樣例

      7

             (1)編程思路。

              采用二進(jìn)制枚舉和容斥原理求解。但由于在M個整數(shù)中選取的若干個數(shù)不一定全部兩兩互質(zhì),可能存在公約數(shù),因此在計算時,需要計算它們的最小公倍數(shù)。

             (2)源程序。

      #include <stdio.h>
      int gcd(int a,int b)
      {
          return a%b==0?b:gcd(b,a%b);
      }
      int main()
      {
          int n,m;
          while (scanf("%d%d",&n,&m)!=EOF)
          {
              int i,j,h=0,a[21];
              for (i=0;i<m;i++)
              {
                  scanf("%d",&a[h]);
                  if (a[h]) h++;      // 過濾掉 0
              }
              m=h;
              int ans=0;
              for (i=1; i<1<<m;i++)  // 二進(jìn)制枚舉各數(shù)的組合情況
              {
                  int cnt=0;         // 組合中選取的數(shù)的個數(shù)(也是對應(yīng)二進(jìn)制數(shù)中1的個數(shù))
                  int t=1;           // 選取各數(shù)的最小公倍數(shù)
                  for (j=0;j<m;j++)
                  {
                      if (i&(1<<j))
                      {
                          cnt++;
                          t=a[j]/gcd(a[j],t)*t;
                      }
                  }
                  if (cnt%2)        // 容斥原理(選1個的情況-選2個的組合+選3個的組合- ……)
                  {
                      ans+=(n-1)/t;
                  }
                  else
                  {
                      ans-=(n-1)/t;
                  }
              }
              printf("%d\n",ans);
          }
          return 0;
      }

             將上面的源程序提交給HDU題庫 HDU 1796 How many integers can you find(http://acm.hdu.edu.cn/showproblem.php?pid=1796),可以Accepted。

      【例2】互質(zhì)的數(shù)

      問題描述

      給定一個整數(shù)N,計算在整數(shù)A和B之間(包括A和B),有多少個整數(shù)與整數(shù)N是互質(zhì)的。

      如果兩個整數(shù)的最大公約數(shù)是1,則稱它們是互質(zhì)的。數(shù)字1與每個整數(shù)都是互質(zhì)的。

      例如,N=2,A=1,B=10時,在[1,10]中有5個整數(shù)與2是互質(zhì)的,它們是{1,3,5,7,9}。

      輸入

      輸入的第一行包含T(0<T<=100)測試用例的數(shù)量,接下來的T行中的每一行包含三個整數(shù)A、B、N,其中(1≤A≤B≤1015)和(1≤N≤109)。

      輸出

      對于每個測試用例,輸出A和B之間的整數(shù)數(shù)(包括A和B),這些整數(shù)與N是互質(zhì)的。

      輸入樣例

      2

      1 10 2

      3 15 5

      輸出樣例

      Case #1: 5

      Case #2: 10

             (1)編程思路。

             先求出整數(shù)n的全部質(zhì)因子,并保存在數(shù)組factor中。之后問題就變成了,分別求1~A-1和1~B之間各有多少個整數(shù)不是數(shù)組factor中的任何一個數(shù)的倍數(shù)。采用上面的二進(jìn)制枚舉和容斥原理進(jìn)行求解。

             (2)源程序。

      #include <stdio.h>
      long long factor[31];
      long long cnt;                   // 整數(shù) n 所含的全部質(zhì)因子的個數(shù)
      void getfac(long long x)         // 求整數(shù)x中的全部質(zhì)因子,并保存到全局?jǐn)?shù)組factor中
      {
          long long i;
          if (x%2==0)
          {
              factor[cnt++]=2;
              while (x%2==0)  x/=2;
          }
          for (i=3;i*i<=x;i+=2)       // 尋找奇數(shù)質(zhì)因子
          {
              if(x%i==0)
              {
                  factor[cnt++]=i;
                  while (x%i==0) x/=i;
              }
          }
          if (x>1) factor[cnt++]=x;
      }
      long long calc(long long x)     // 計算1~x之間不能被數(shù)組factor中任一質(zhì)因子整除的數(shù)的個數(shù)
      {
          long long sum=0;
          long long i,j;
          for (i=1;i<(1<<cnt);i++)    // 二進(jìn)制枚舉,所有質(zhì)因子的組合情況
          {
              long long num=0;        // 從質(zhì)因子集合中選擇質(zhì)因子的個數(shù)
              long long ans=1;        // ans為質(zhì)因子積;
              for (j=0;j<cnt;j++)     // 枚舉質(zhì)因子下標(biāo)
              {
                  if ((i>>j)&1)       // 第j個質(zhì)因子被選取
                  {
                      num++;
                      ans*=factor[j];
                  }
              }
              if (num&1) sum+=x/ans;  // 容斥原理,奇+偶-,1~x中為ans倍數(shù)的數(shù)的個數(shù)x/ans
              else  sum-=x/ans;
          }
          return x-sum;
      }
      int main()
      {
          int t,iCase=0;
          scanf("%d",&t);
          while (t--)
          {
              long long a,b,n;
              scanf("%lld%lld%lld",&a,&b,&n);
              cnt=0;
              getfac(n);
              long long x,y;
              x=calc(a-1);
              y=calc(b);
              printf("Case #%d: %lld\n",++iCase,y-x);
          }
          return 0;
      }

             將上面的源程序提交給HDU題庫 HDU 4135 Co-prime (http://acm.hdu.edu.cn/showproblem.php?pid=4135),可以Accepted。

             在HDU題庫中,還有2道題目與例2類似,給出參考源程序如下。

             HDU 1695  GCD (http://acm.hdu.edu.cn/showproblem.php?pid=1695)。

      #include <stdio.h>
      #include <string.h>
      long long calc(long long n,long long m)    // 求區(qū)間[1,m]內(nèi)與n互質(zhì)的數(shù)的個數(shù)
      {
          long long factor[31];     // 求出整數(shù)n中的全部質(zhì)因子保存在數(shù)組factor中
          long long len=0;        // n中質(zhì)因子的個數(shù)
          long long i,j;
          if (n%2==0)
          {
              factor[len++]=2;
              while (n%2==0)  n/=2;
          }
          for (i=3;i*i<=n;i+=2)      // 尋找奇數(shù)質(zhì)因子
          {
              if(n%i==0)
              {
                  factor[len++]=i;
                  while (n%i==0) n/=i;
              }
          }
          if (n>1) factor[len++]=n;
          long long sum=0;
          for (i=1;i<(1<<len);i++)    // 二進(jìn)制枚舉,所有質(zhì)因子的組合情況
          {
              long long cnt=0;      // 從質(zhì)因子集合中選擇質(zhì)因子的個數(shù)
              long long p=1;       // p為質(zhì)因子積;
              for (j=0;j<len;j++)     // 枚舉質(zhì)因子下標(biāo)
              {
                  if ((i>>j)&1)      // 第j個質(zhì)因子被選取
                  {
                      cnt++;
                      p*=factor[j];
                  }
              }
              if (cnt&1) sum+=m/p;  //容斥原理,奇+偶-,1~m中為p倍數(shù)的數(shù)的個數(shù)m/p
              else  sum-=m/p;
          }
          return m-sum;
      }
      int main()
      {
          int t,iCase=0;
          scanf("%d",&t);
          while (t--)
          {
              long long a,b,c,d,k;
              scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&k);
              if(k==0)
              {
                  printf("Case %d: 0\n",++iCase);
                  continue;
              }
              b/=k;  d/=k;
              if (b>d)
              {
                  long long temp;
                  temp=b;  b=d;  d=temp;
              }
              long long i,ans=0;
              for (i=1;i<=d;i++)
              {
                  long long k;
                  k=i<b?i:b;
                  ans+=calc(i,k);       // 求區(qū)間[1,k]內(nèi)與i互質(zhì)的個數(shù)
              }
              printf("Case %d: %lld\n",++iCase,ans);
          }
          return 0;
      }
      參考源程序

             HDU 2841 Visible Trees(http://acm.hdu.edu.cn/showproblem.php?pid=2841)。

      // 如果gcd(x,y)=z,gz!=1,那么一定被(x/z,y/z)的點(diǎn)擋住
      // 即兩個數(shù)字(x,y)如果互質(zhì),則可以被看到;如果不互質(zhì),則看不到.
      // 所以本題就是要找出所有的互質(zhì)二元組(x,y)
      // 因此問題的最后變成:給定一個數(shù)x,找出它和1到y(tǒng)里面有多少個數(shù)互質(zhì)。
      #include <stdio.h>
      #include <string.h>
      long long calc(long long n,long long m)     // 求區(qū)間[1,m]內(nèi)與n互質(zhì)的數(shù)的個數(shù)
      {
          long long factor[31];       // 求出整數(shù)n中的全部質(zhì)因子保存在數(shù)組factor中
          long long len=0;          // n中質(zhì)因子的個數(shù)
          long long i,j;
          if (n%2==0)
          {
              factor[len++]=2;
              while (n%2==0)  n/=2;
          }
          for (i=3;i*i<=n;i+=2)       // 尋找奇數(shù)質(zhì)因子
          {
              if(n%i==0)
              {
                  factor[len++]=i;
                  while (n%i==0) n/=i;
              }
          }
          if (n>1) factor[len++]=n;
          long long sum=0;
          for (i=1;i<(1<<len);i++)    // 二進(jìn)制枚舉,所有質(zhì)因子的組合情況
          {
              long long cnt=0;      // 從質(zhì)因子集合中選擇質(zhì)因子的個數(shù)
              long long p=1;       // p為質(zhì)因子積;
              for (j=0;j<len;j++)     // 枚舉質(zhì)因子下標(biāo)
              {
                  if ((i>>j)&1)       // 第j個質(zhì)因子被選取
                  {
                      cnt++;
                      p*=factor[j];
                  }
              }
              if (cnt&1) sum+=m/p;  //容斥原理,奇+偶-,1~m中為p倍數(shù)的數(shù)的個數(shù)m/p
              else  sum-=m/p;
          }
          return m-sum;
      }
      int main()
      {
          int t;
          scanf("%d",&t);
          while (t--)
          {
              long long  m,n;
              scanf("%lld%lld",&m,&n);
              long long i,ans=0;
              for (i=1;i<=m;i++)
              {
                  ans+=calc(i,n);
              }
              printf("%lld\n",ans);
          }
          return 0;
      }
      參考源程序

      posted on 2022-11-26 08:38  aTeacher  閱讀(197)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 这里只有精品在线播放| 米奇影院888奇米色99在线| 精品久久欧美熟妇www| 精品久久久久久国产| 蜜臀av久久国产午夜| 亚洲精品日韩中文字幕| 亚洲 成人 无码 在线观看| 国产成人亚洲精品日韩激情| 中文字幕久久久久人妻 | 懂色AV| 九九视频热最新在线视频| 国语精品一区二区三区| 少妇人妻真实偷人精品| 亚洲日韩久热中文字幕| 午夜免费福利小电影| 欧美视频二区欧美影视| 国产精品三级中文字幕| 人人妻人人爽人人澡av| 中文字幕亚洲男人的天堂| 久久精品国产中文字幕| 婷婷国产成人精品视频| 亚洲精品一区二区三区小| 亚洲日韩久热中文字幕| 成人网站免费观看永久视频下载| 98日韩精品人妻一二区| 国产成A人片在线观看视频下载 | 亚洲av伊人久久综合性色| 国偷自产一区二区三区在线视频 | 国内外精品激情刺激在线| 亚洲最大的熟女水蜜桃AV网站| 99中文字幕国产精品| 国产免费性感美女被插视频| 亚洲VA成无码人在线观看天堂| 亚洲成人av在线系列| 欧美日韩在线亚洲二区综二| 亚洲理论在线A中文字幕| 秋霞鲁丝片av无码少妇| 色综合久久精品中文字幕| 国产精品午夜福利资源| 成人免费无遮挡在线播放| 日韩精品成人区中文字幕|