链接:HDU 6156
题意
给定l, r, L, R, 求
∑Ri=L∑rj=lf(i,j)
其中
题解
推一下式子:
令
F(N,d)=∑Ni=1[f(i,d)=d]
则
那么, 只要求出 F(N,d)(1<=N<=1e9,2<=d<=36) 就可以了
设N的d进制为:
即:
Nd=NnNn−1....N0
我们的目的是要找出不[1, N]中在d进制下回文数的个数.
很容易得到这些数在d进制下的位数最大为n+1
设目标数为i
1. 考虑i在d进制下是1位, (若n>=1)那么i <= N一定满足,i在当前位的数范围为[1, d - 1]
此时满足条件的i个数为d - 1
2. 考虑i在d进制下是2位,若n>=2, i一定满足i<= N, 只要满足
i0=i1
即可, 同样是d - 1
3. 考虑i在d进制下是bit位的
3<=bit<=n
i满足i<= N,
i0=ibit−1范围为[1,d−1]
而中间的bit-2位, 回文位取相等即可就是
(d−1)∗d⌈bit−22⌉
4. 考虑i在d进制下是n + 1位
1)
in<Nn
,
in
取值有
Nn−1
种且
in=i0
中间回文位取相等即为
(Nn−1)∗d⌈n−12⌉
2)
in=Nn
这时候如果
Nn<=N0
直接考虑中间位即可
否则要向前借位
dfs计数即可(dfs过程中i位数是固定的所以只要考虑4)
这题昨天现场20分钟出思路, 结束之前没交上正解, 太弱~
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll L, R, l, r;
ll a[35];
ll qpow(ll a, ll b)
{
ll res = 1;
while(b)
{
if(b & 1) res *= a;
a *= a;
b >>= 1;
}
return res;
}
ll Div(ll x)
{
return x % 2 == 0 ? x / 2 : x / 2 + 1;
}
ll Cal(ll d, ll bit)
{
return 2 * (qpow(d, bit / 2 + 1) - d) / (d - 1) + (bit & 1 ? qpow(d, (bit + 1) /2) : 0);
}
ll dfs(ll a[], ll cnt, ll d)
{
if(cnt < 0) return 1;//这里有一个计数
if(cnt == 0) return a[cnt] + 1;//[0, a[cnt]]
ll num = 0;
num += a[cnt] * (cnt == 1 ? 1 : qpow(d, (ll)Div(cnt - 1)));//4.1)
if(a[cnt] > a[0])//4.2)借位
{
--a[1];
ll id = 1;
while(a[id] < 0 && id < cnt)
{
a[id] += d;
--a[++id];
}
if(id == cnt) return num;
}
return num + dfs(a + 1, cnt - 2, d);
}
ll cal(ll x, ll d)
{
ll cnt = 0;
ll tmp = x;
while(tmp)
{
a[cnt++] = tmp % d;
tmp /= d;
}
cnt = cnt - 1;
if(cnt < 0) return 0;
if(cnt == 0) return a[cnt];
ll num = 0;
num += (a[cnt] - 1) * (cnt == 1 ? 1 : qpow(d, Div(cnt - 1))) + (cnt > 2 ? (d - 1) * Cal(d, cnt - 2) : 0)+ (d - 1) * (cnt >= 2?2:1);//要根据位数判断计数
if(a[cnt] > a[0])//借位
{
--a[1];
ll id = 1;
while(a[id] < 0 && id < cnt)
{
a[id] += d;
--a[++id];
}
if(id == cnt) return num;
}
return num + dfs(a + 1, cnt - 2, d);
}
int main(){
//freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
int T, kas = 0;
scanf("%d", &T);
while(T--)
{
scanf("%d%d%d%d", &L, &R, &l, &r);
ll ans = 0;
for(int i = l; i <= r; ++i)
{
// cout << i << " " <<cal(R, i) << " " <<cal(L - 1, i) << endl;
ans += (ll)(R - L + 1) + (i - 1) * (cal(R, i) - cal(L - 1, i));
// cout << ans << endl;
}
printf("Case #%d: %lld\n", ++kas, ans);
}
return 0;
}