第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(济南)-L Bit Sequence

题意

给你两个数l,m,大小为m的数组a,求[0,l]之间满足以下条件的数x的个数:
对于任何i输入[0,m-1],f(x+i)%2=a[i];f(k):代表k在二进制下1的个数
m的范围<=100,l<=1e18,a[i] = 0/1

思路

显然l的范围1e18,大概率就是数位DP了

  1. 观察到m是<=100的,因此x+m只会改变后7位置,对于前面的位数,则只会进1,使得前面连续的0变成1;
  2. 那么只要对前半部分进行数位DP,dp[pos][lim][cnt][d]代表位置在pos处,lim代表有无达到上限,cnt为1代表前面有奇数个1为0代表偶数个1,d代表从pos起向前有偶数还是奇数个1;
  3. 对于第七位以后的部分,直接暴力计算就好了,统计以下是否进位;

代码

#include <bits/stdc++.h>  using namespace std;  #define nl "n" #define nf endl #define ll long long #define pb push_back #define _ << ' ' <<  #define INF (ll)1e18 #define mod 998244353 #define maxn 110 #define lc 1338557220  ll i, i1, j, k, k1, t, n, m, res, flag[10], a, b; ll x, rs[maxn], p; vector<ll> pw = {23, 19, 17, 13, 11, 9, 7, 5, 4};  ll ask(ll a, ll b) {    cout << "?" _ a _ b << nf;    ll x;    cin >> x;    return x; }  void clm(ll x) {    cout << "!" _ x << nf; }  int main() {    ios::sync_with_stdio(0);    cin.tie(0);     /* #if !ONLINE_JUDGE && !EVAL        ifstream cin("input.txt");        ofstream cout("output.txt");    #endif */     // kudos for automatic wa     cin >> t;    while (t--) {        for (i = 1; i <= 23; i++) {            k = ask(x + i, lc + i);            for (j = 0; j < 9; j++) {                if (k % pw[j] == 0) rs[j] = (-i % pw[j] + pw[j]) % pw[j];            }        }         k = 1;        p = 1;        for (j = 0; j < 9; j++) {            // cout << "p =" _ p << nf;            while (p % pw[j] != rs[j]) p += k;            k *= pw[j];        }         clm(p);    }    return 0; } 

发表评论

评论已关闭。

相关文章