1. 程式人生 > 實用技巧 >AIsing Programming Contest 2020 D - Anything Goes to Zero

AIsing Programming Contest 2020 D - Anything Goes to Zero

題目連結:https://atcoder.jp/contests/aising2020/tasks/aising2020_d

題意:給一個位數為 1~2e5的 數 (可能有前置0)定義f(x)為x對popcount(x) 取模 每一位都要取反一次,(進行到下一位的時候,上面恢復原樣)

問沒一位數要 f 幾次

思路:首先考慮大數的問題,開始去找 幾個1 和取模的數有無規律 發現沒有

那麼就要處理掉這個大數,肯定是要通過取模來使得數變小,並且取模的數是固定的 假設sum為字串中1的總數 那麼取模要麼是sum-1 要麼就是sum+1 對應1和0

那麼就可以處理出 sum1 為取模後的大數的值,sum0 也為取模後的大數的值 在遍歷字串的時候 遇到1 用sum1 減去當前的值即可, 遇到0 用sum0+上當前的值即可

因為f 函式 每次取模後剩下的都是1的個數以內的數 所以複雜度是logn 以內的

唯一要注意的就是 sum-1 為0時要討論以下, 不能對0取模

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define ull unsigned long long
 5 #define pb push_back
 6 const int maxn=2e5+10;
 7 const int mod=1e9+7;
 8 char s[maxn];
 9 vector<int>ans;
10 int f(int x) 11 { 12 int cnt=0; 13 while(x) 14 { 15 x%=__builtin_popcount(x); 16 cnt++; 17 } 18 return cnt+1; 19 } 20 ll power(ll base,ll n,ll m) 21 { 22 ll r=1; 23 while(n) 24 { 25 if(n&1) r=r*base%m; 26 base=base*base%m; 27 n/=2
; 28 } 29 return r; 30 } 31 32 int main() 33 { 34 ios::sync_with_stdio(false); 35 cin.tie(0); 36 int n; 37 cin>>n; 38 cin>>(s+1); 39 int sum=0; 40 for(int i=1;i<=n;i++) 41 { 42 if(s[i]=='1') 43 sum++; 44 } 45 ll sum1=0; 46 ll sum0=0; 47 reverse(s+1,s+1+n); 48 for(int i=1;i<=n;i++) 49 { 50 if(s[i]=='1') 51 { 52 sum0+=power(2,i-1,sum+1); 53 sum0%=(sum+1); 54 if(sum-1==0) 55 continue; 56 sum1+=power(2,i-1,sum-1); 57 sum1%=(sum-1); 58 59 } 60 } 61 for(int i=1;i<=n;i++) 62 { 63 if(s[i]=='1') 64 { 65 if(sum-1==0) 66 { 67 ans.pb(0); 68 continue; 69 } 70 ll temp=sum1-power(2,i-1,sum-1); 71 temp=(temp+sum-1)%(sum-1); 72 ans.pb(f(temp)); 73 } 74 else 75 { 76 ll temp=sum0+power(2,i-1,sum+1); 77 temp%=sum+1; 78 ans.pb(f(temp)); 79 } 80 } 81 reverse(ans.begin(),ans.end()); 82 for(auto &v:ans) 83 cout<<v<<'\n'; 84 85 86 87 88 89 90 91 92 93 }
View Code