CF#739-D Make a Power of Two
阿新 • • 發佈:2021-08-22
整局連結:Codeforces Round #739 (Div. 3)
題目大意:
給一個數字,你可以有以下兩種操作:
1.刪除任意數位上的數字;2.在最右邊加上一個數位
問最少經過多少次操作這個數字可以變成2的次方。
思路:
一開始我以為是數位dp直接GG
//以下文字結合程式碼看比較好理解
實際上,只要把給定的數和所有2的次方比較求答案取最小值就行了。當然,2的次方不會是無限個,這題的資料範圍只需要到60次就行。那怎麼去比較呢,可以用子序列的思想。設2的次方是a,給定的是b,我們要找b裡面形如a的子序列(可能不是完整的)。
在b中如果找到不一樣的,就是說要刪掉這個數位。上圖中顏色一樣的就是對應相等的,而b[2]就是應該刪掉的數位。
設指向a的是i,指向b的是j。
當ij指標中有一個走完後,有四種情況:i沒走完,j沒走完,ij都沒走完,ij都走完。
i < la :i沒走完,就是說要b變成a,就要加上a中i後面的那些數字
j < lb :j沒走完,就是說b要變成a,就要減去b中j後面的那些數字
程式碼:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int INF = 0x3f3f3f3f; const int N = 2*1e8+10; string s[70] = {"1","2","4","8","16","32","64","128","256","512","1024","2048","4096","8192","16384","32768","65536","131072","262144","524288","1048576","2097152","4194304","8388608","16777216","33554432","67108864","134217728","268435456","536870912","1073741824","2147483648","4294967296","8589934592","17179869184","34359738368","68719476736","137438953472","274877906944","549755813888","1099511627776","2199023255552","4398046511104","8796093022208","17592186044416","35184372088832","70368744177664","140737488355328","281474976710656","562949953421312","1125899906842624","2251799813685248","4503599627370496","9007199254740992","18014398509481984","36028797018963968","72057594037927936","144115188075855872","288230376151711744","576460752303423488","1152921504606846976"};//這個是1~2**60的打表拿另外一個程式寫很快的。 string t; int T; inline ll read(){//快讀 ll ans = 0; char c = getchar(); while (!isdigit(c)) c = getchar(); while (isdigit(c)){ ans = ans * 10 + c - '0'; c = getchar(); }return ans; } int solve(string a,string b){ int i = 0,j = 0,res = 0; int la = a.length(),lb = b.length(); while(i < la && j < lb){ if(a[i] == b[j])++i,++j; else{ while(j < lb && a[i] != b[j])++j,++res; } } if(i < la)res += la - i;//a沒走完,要在最後加數字 if(j < lb)res += lb - j;//b沒走完,要在最後刪數字 //cout<<a<<"======================>"<<res<<"\n"; return res; } int main(){ T = read(); while(T--){ cin>>t; int ans = INF; for(int i = 0;i < 61; i++)//對和所有2的次方的比較中取最小值 ans = min(ans,solve(s[i],t)); cout<<ans<<"\n"; } }