2020CCPC长春 D. Meaningless Sequence(打表/数位DP)

Once there was a mathematician, who was obsessed with meaningless number sequences. Here is one of them.

={1,⋅max0≤<&,=0otherwise,an={1,n=0c⋅max0≤i<nan&⁡i,otherwise,

where && denotes the bitwise AND operation.

As a mathematician, he could easily tell what an was for any n, but he wanted to test you. You are required to tell him

(∑=0)mod(109+7)(∑i=0nai)mod(109+7)

to convince him that you have a deep understanding of this (although meaningless) sequence.

先打一个表找规律,发现其实很难看出来。考虑到规律可能与c的取值无关,于是打印一下每个位置n对应的最大的\(a_{n \& i}\)所在的位置,发现这个位置实际上就是n去掉最高位的1,于是每个位置n对应的值实际上就是\(c^{n的二进制表示中1的个数}\)。由于答案要求所有数的和,且注意到位与位之间彼此无关,可以考虑数位dp求解。设dp[i, j, k]表示当前遍历到len,且当前位为j,是否紧贴边界为k的答案。直接套板子即可。

#include <iostream>
#define ll long long
#define mod 1000000007
using namespace std;
//string n;
ll c;
string n;
ll fpow(ll a, ll b) {
	ll ans = 1;
	for(; b; b >>= 1) {
		if(b & 1) ans = ans * a % mod;
		a = a * a % mod;
	}
	return ans;
}
ll get(ll x) {
	int ans = 0;
	while(x) {
		if(x & 1) ans++;
		x >>= 1;
	}
	return ans;
}
ll dp[3005][2][2];
bool num[3005];
int nn = 0;
ll dfs(ll len, bool pre, bool tight) {
	if(dp[len][pre][tight]) return dp[len][pre][tight];
	if(len == 0) return 1;
	ll ans = 0;
	for(ll i = 0; i < 2; i++) {
		if(i == 0) ans = (ans + dfs(len - 1, 0, tight && (i == num[len]))) % mod;
		else {//这一位如果是1的话,上一位肯定不能是1,同时要注意不能超边界
			if(i > num[len] && tight) continue;
			ans = (ans + c * dfs(len - 1, 1, tight && (i == num[len])) % mod) % mod;
		}
	}

	return dp[len][pre][tight] = (ans % mod);
}
int main() {
	cin >> n >> c;
	for(int i = n.size() - 1; i >= 0; i--) {
		if(n[i] == '0') num[++nn] = 0;
		else num[++nn] = 1;
	}
	//从0到n c的每个数中1的个数次方
	
	cout << dfs(nn, 0, 1) % mod;
	return 0;
}
原文地址:https://www.cnblogs.com/lipoicyclic/p/15538664.html