第 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  int long long
int a[105];
vector<int> b;
int mp[80][2][2][2];
int mx;
int m, l;

int clc(int lim, int cnt, int h) {
   int up = (1 << 7) - 1;
   if (lim) up = mx;
   int all = 0;
   int cc = cnt;
   for (int i = 0; i <= up; i++) {
       bool flag = 1;
       for (int j = 0; j < m; j++) {
           cnt = cc;
           int res = i + j;
           int sum = __builtin_popcount(res);
           cnt += sum;
           cnt &= 1;
           if (res > ((1 << 7) - 1))cnt = (cnt + h) & 1;
           if (cnt != a[j])flag = 0;
       }
//        if (flag)cout << i << '\n';
       all += flag;
   }
   return all;
}

long long DFS(int pos, int lim, int cnt, int h) {
   if (mp[pos][lim][cnt][h] != -1)return mp[pos][lim][cnt][h];
   long long ans = 0;
   if (pos <= 6)return clc(lim, cnt, h);
   if (lim) {
       for (int i = 0; i <= b[pos]; i++) {
           bool ok = (i == b[pos]);
           int hh = 0;
           if (i == 0)hh = 0;
           else
               hh = (h + 1) & 1;
           ans += DFS(pos - 1, ok, (cnt + (i == 1)) & 1, hh);
       }
   } else {
       for (int i = 0; i <= 1; i++) {
//            bool ok = (i == b[pos]);
           int hh = 0;
           if (i == 0)hh = 0;
           else
               hh = (h + 1) & 1;
           ans += DFS(pos - 1, 0, (cnt + (i == 1)) & 1, hh);
       }
   }
   return mp[pos][lim][cnt][h] = ans;
}

void run() {

   cin >> m >> l;
   for (int i = 0; i < m; i++) {
       cin >> a[i];
   }
   b.clear();
   memset(mp, -1, sizeof mp);
   for (int i = l; i; i >>= 1) {
       b.emplace_back(i & 1);
   }
   mx = l & ((1 << 7) - 1);
   cout << DFS(b.size() - 1, 1, 0, 0) << '\n';


}

signed main() {

   int t;
   cin >> t;
   while (t--)
       run();
   return 0;
}

posted @ 2022-11-03 21:48  4VDP  阅读(379)  评论(0编辑  收藏  举报