日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

信息学奥赛一本通 1223:An Easy Problem | OpenJudge NOI 4.6 1455:An Easy Problem

發(fā)布時(shí)間:2025/3/17 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 信息学奥赛一本通 1223:An Easy Problem | OpenJudge NOI 4.6 1455:An Easy Problem 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

【題目鏈接】

ybt 1223:An Easy Problem
OpenJudge NOI 4.6 1455:An Easy Problem

【題目考點(diǎn)】

1. 數(shù)制

2. 枚舉

【解題思路】

解法1:枚舉

要找比給定數(shù)字n大的最小的二進(jìn)制表示中1的個(gè)數(shù)相同的數(shù)字。
先求出n在二進(jìn)制表示下1的個(gè)數(shù)。
而后不斷枚舉比n大的整數(shù),求出其二進(jìn)制表示中1的個(gè)數(shù)。如果1的個(gè)數(shù)與n在二進(jìn)制下1的個(gè)數(shù)相同,那么就是找到了比n大的最小的二進(jìn)制表示中1的個(gè)數(shù)相同的數(shù)字。

分析算法最大復(fù)雜度:n最大是10610^6106,二進(jìn)制下各位全是1的情況,需要枚舉的次數(shù)最多。
已知一個(gè)x位二進(jìn)制數(shù)11?1?x\underbrace {11\cdots 1}_xx11?1??,各位都是1,其數(shù)值為2x?12^x-12x?1
2x?1≤1062^x-1 \le 10^62x?1106,有x≤log2(106+1)≈19.9x \le log_2(10^6+1)\approx 19.9xlog2?(106+1)19.9,x最大為19。考慮比11?1?19\underbrace{11\cdots 1}_{19}1911?1??大的最小的也有19個(gè)1的二進(jìn)制數(shù)字,為1011?1?1810\underbrace{11\cdots 1}_{18}101811?1??,相當(dāng)于比1011?1?18?11?1?19=100?0?18=218=26214410\underbrace{11\cdots 1}_{18}-\underbrace{11\cdots 1}_{19}=1\underbrace{00\cdots 0}_{18} = 2^{18}=262144101811?1???1911?1??=11800?0??=218=262144
即對(duì)于每個(gè)數(shù)字,至多枚舉262144次,即可得到解,每次枚舉拆分?jǐn)?shù)字要循環(huán)10次。
對(duì)于每個(gè)數(shù)字,運(yùn)算復(fù)雜度最大為10610^6106數(shù)量級(jí)。該算法可以支持在1秒內(nèi)對(duì)10~100個(gè)數(shù)字求比給定數(shù)字大的最小的二進(jìn)制表示中1的個(gè)數(shù)相同的數(shù)字。題目沒(méi)說(shuō)要輸入多少數(shù)字,默認(rèn)不說(shuō)就是小于等于100個(gè)。所以該算法是可行的。

解法2:找規(guī)律

思考,如果該二進(jìn)制數(shù)末尾幾位是0,增加1后,其中1的個(gè)數(shù)就多了1個(gè)。再增加1,1的個(gè)數(shù)始終是變多的。如果數(shù)值增加后改變的位置其原位置上都是0,那么1的數(shù)量就不會(huì)減少到與原有1的數(shù)量相同。

原數(shù)字:1000
加1:1001
加1:1010
加1:1011
1的數(shù)量始終比1000要多。

只有當(dāng)增加的數(shù)值與原位置上的1加和引發(fā)進(jìn)位,才會(huì)使1的數(shù)量減少

原數(shù)字:1011
加1:1100:減少兩位1,增加一個(gè)進(jìn)位的1。總共減少一位1。

觀察規(guī)律可知,第一次1減少的時(shí)機(jī)發(fā)生在最末尾一段連續(xù)的1發(fā)生進(jìn)位的時(shí)候。
嚴(yán)格描述為:二進(jìn)制數(shù)字d1d2?dx?x011?1?k00?0?m\underbrace{d_1d_2\cdots d_x}_x0\underbrace{11\cdots 1}_{k}\underbrace{00\cdots 0}_{m}xd1?d2??dx???0k11?1??m00?0??d1~dxd_1\sim d_xd1?dx?為任意數(shù)字。其中x,m最小為0,k最小為1)
該數(shù)字在增加100?0?m1\underbrace{00\cdots 0}_{m}1m00?0??后發(fā)生進(jìn)位,成為d1d2?dx?x100?0?k+m\underbrace{d_1d_2\cdots d_x}_x1\underbrace{00\cdots 0}_{k+m}xd1?d2??dx???1k+m00?0??,這次進(jìn)位增加了1位1,減少了k位1,所以共減少k-1位1。
為了讓1的數(shù)量不發(fā)生改變,應(yīng)該在末尾增加k-1位1,使數(shù)字變?yōu)?#xff1a;d1d2?dx?x100?0?m+111?1?k?1\underbrace{d_1d_2\cdots d_x}_x1\underbrace{00\cdots 0}_{m+1}\underbrace{11\cdots 1}_{k-1}xd1?d2??dx???1m+100?0??k?111?1??

具體做法為

  • 將數(shù)字轉(zhuǎn)為二進(jìn)制形式,存入數(shù)組
  • 從低位向高位遍歷,如果發(fā)現(xiàn)當(dāng)前位是1且下一位是0的情況,說(shuō)明找到了最末尾一段連續(xù)的1的最高位,記為b。
  • b+1位置從0變?yōu)?。如果b本身是數(shù)字的最高位,將b+1位置設(shè)為最高位。
  • 從b開(kāi)始向低位遍歷,計(jì)數(shù)得到有k個(gè)連續(xù)的1,同時(shí)將遍歷到的位置從1變?yōu)?。
  • 從末尾位開(kāi)始,連續(xù)將k-1位0變?yōu)?。
  • 輸出數(shù)字。
  • 該算法針對(duì)每個(gè)數(shù)字,只是對(duì)數(shù)字各位進(jìn)行幾遍遍歷。小于等于10610^6106的數(shù)字的二進(jìn)制位為20位左右。因而針對(duì)每個(gè)數(shù)字的運(yùn)算次數(shù)都是101010數(shù)量級(jí)。復(fù)雜度遠(yuǎn)小于方法1。

    【題解代碼】

    解法1:枚舉

    #include<bits/stdc++.h> using namespace std; int main() {int n, ans;while(cin >> n && n != 0){int ct_n = 0, ct_a;//ct_n:n中1的個(gè)數(shù) ct_a:ans中1的個(gè)數(shù) for(int a = n; a > 0; a /= 2)if(a%2 == 1)ct_n++;for(ans = n+1; true; ans++){ct_a = 0;for(int a = ans; a > 0; a /= 2)if(a%2 == 1)ct_a++;if(ct_a == ct_n){cout<< ans << endl;break;}}}return 0; }

    解法2:找規(guī)律(復(fù)雜度低)

    //找最末的連續(xù)k個(gè)1,變?yōu)?加上k個(gè)0,末尾再添加k-1個(gè)1 #include <bits/stdc++.h> using namespace std; int main() {int n, num[50];while(cin >> n && n != 0){memset(num, 0, sizeof(num));int b, ct = 0, ni = 0, ans = 0;//b:最末連續(xù)的1的起始位置for(int a = n; a > 0; a /= 2)num[++ni] = a % 2;for(int i = 1; i <= ni; ++i){if(num[i] == 1 && num[i+1] == 0){b = i;break;}}num[b+1] = 1;if(b+1 > ni)ni = b+1;for(int i = b; num[i] != 0; --i){ct++;num[i] = 0;}for(int i = 1; i <= ct-1; ++i)num[i] = 1;for(int i = ni; i >= 1; --i)ans = ans*2+num[i];cout << ans << endl;} return 0; }

    總結(jié)

    以上是生活随笔為你收集整理的信息学奥赛一本通 1223:An Easy Problem | OpenJudge NOI 4.6 1455:An Easy Problem的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。