AtCoder Beginner Contest 129
E
想不到是dp,看不出来
对于一个数字L,要想使的a+b = a^b <= L
那么只能当前这一位只能选(0,1)(1,0)(0,0)
如果选(1,1)产生进位有可能不和规定
规定dp[i][0/1]表示在第i位选的数严格小于L/等于L的情况
考虑dp[i][1],如果L第i位为1,我们可以选择(0,1)(1,0)两个方案,否则只能选择(0,0),所以dp[i][1] = dp[i-1][1] + [L[i]==1]*dp[i-1][1]
考虑dp[i][0],因为dp[i-1][0]已经严格小于了L,所以可以选任意三种,但是如果前面严格等于并且第i为是1,我们也可以选择用(0,0)满足严格小于L的方案,所以dp[i][0] = 3 * dp[i-1][0] + [L[i] == 1] * dp[i-1][1]
const int mod = 1e9+7;
const int MAXN = 1e5+5;
int a[MAXN];
ll dp[MAXN][2];
int main()
{
string op;
cin >> op;
int n = op.size();
for(int i = 0; i < n; i++)
{
a[i+1] = op[i] - '0';
}
dp[1][1] = 2;
dp[1][0] = 1;
for(int i = 2; i <= n; i++)
{
dp[i][0] = dp[i-1][0] * 3;
if(a[i] == 0)
{
dp[i][1] = dp[i-1][1];
}
else
{
dp[i][0] += dp[i-1][1];
dp[i][1] = dp[i-1][1] * 2;
}
dp[i][0] %= mod, dp[i][1] %= mod;
}
cout << (dp[n][0] + dp[n][1]) % mod << endl;
}
F
看到递推加速很容易想到矩阵快速幂
S
i
=
S
i
−
1
∗
1
0
d
+
A
i
S_i = S_{i-1} * 10^d + A_{i}
Si=Si−1∗10d+Ai
A
i
=
A
i
−
1
+
B
A_i = A_{i-1} + B
Ai=Ai−1+B
很容易构造出矩阵
关键是
1
0
d
10^d
10d不好用矩阵得到
1
0
d
+
1
10^{d+1}
10d+1
只要我们在 1 0 d − ( 1 0 d + 1 − 1 ) 10^{d} - (10^{d+1}-1) 10d−(10d+1−1)范围内的数即可,算完之后d++,一直到最后就好。意思就是分数字长度计算每一段的S
每一段要计算的递推长度用二分查找即可
const int MAXN = 5;
ll mod;
struct mat
{
int n, m;
unsigned long long a[MAXN][MAXN];
mat(){
memset(a, 0, sizeof(a));
}
mat(int aa, int b) : n(aa), m(b){
memset(a, 0, sizeof(a));
}
void ones()
{
for(int i = 0; i < n; i++)
{
a[i][i] = 1;
}
}
mat operator *(mat p)
{
mat ret(n, p.m);
for(int i = 0; i < n; i++)
{
for(int j = 0; j < p.m; j++)
{
ll sum = 0;
for(int k = 0; k < m; k++)
{
sum += ((a[i][k] % mod) * (p.a[k][j] % mod)) % mod;
sum %= mod;
}
ret.a[i][j] = sum;
}
}
return ret;
}
};
mat qpow(mat a, ll b)
{
mat ans(3, 3);
ans.ones();
mat base = a;
while(b)
{
if (b & 1)
{
ans = ans * base;
}
base = base * base;
b >>= 1;
}
return ans;
}
int main()
{
//FIN;
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll log10 = 10;
ll L ,aa, bb;
cin >> L >> aa >> bb >> mod;
ll A = aa, B = bb;
mat ans(1, 3);
ans.a[0][1] = A;
ans.a[0][2] = B;
ll pos = 0;
for(ll p = 1; p <= 19; p++)
{
ll l = pos, r = L - 1;
ll tans = -1;
while(l <= r)
{
ll mid = (l + r) >> 1;
if(A + mid * B < log10 )
{
l = mid + 1;
tans = mid;
}
else
{
r = mid - 1;
}
}
if(tans == -1)
{
if(pos > L - 1) break;
log10 *= 10;
continue;
}
mat base(3, 3);
base.ones();
base.a[0][0] = log10;
base.a[1][0] = 1;
base.a[2][1] = 1;
ans = ans * qpow(base, tans - pos + 1);
pos = tans + 1;
if(pos > L - 1) break;
log10 *= 10;
}
cout << ans.a[0][0] << endl;
return 0;
}