Codeforces Round #701 (Div.2)
A. Add and Divide
不难想到,最优解一定是\(b\)先加到某个值\(b'\)后再通过不断除而成。
答案即为\(\min \{n + \left \lfloor \log_{b + n} {a} \right \rfloor + 1\}\),\(n\)为\(b\)加了几次。
可以想出答案不会超过\(30\),枚举\(n\)即可。
# include <bits/stdc++.h>
using namespace std;
int t;
int a,b;
int qfind(int a,int b)
{
long long cur = 1;
if(a == 1) return 1;
if(b == 1) return 1e9 + 7;
for(int i = 1; i <= 31; i++)
{
cur *= b;
if(cur > a) return i;
else if(cur == a) return i + 1;
}
}
int main(void)
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&a,&b);
if(a < b)
{
printf("1\n");
continue;
}
if(a == b)
{
printf("2\n");
continue;
}
int ans = 31;
for(int n = 0; n <= 30; n++)
{
int P = qfind(a,b + n);
ans = min(ans,P + n);
// printf("n = %lld,b + n = %lld,P = %lld\n",n,b + n,P);
}
printf("%d\n",ans);
}
return 0;
}
B. Replace and Keep Sorted
考虑对于第\(i\)个位置上可以改成几个数是合法的。
- 对于\(i = 1\),则整数\(x\)满足\(x \in [1,a_2)\)是合法的。
- 对于\(i = n\),则整数\(x\)满足\(x \in (a_{n - 1},k]\)是合法的。
- 对于\(1 < i < n\),则整数\(x\)满足\(x \in (a_{i - 1},a_{i + 1})\)是合法的。
令\(b_i\)为第\(i\)个位置上能够修改的数的个数,减一下就珂以了,别忘了减一(不能和\(a_i\)一样)
然后\(sum_i\)维护一下\(b_i\)前缀和,对于每个询问\(l_i,r_i\),答案为\(Sum(l_i + 1,r_i - 1)\)再加上两边的个数,因为两边不受限制了。
# include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n,q,k;
int a[N];
int b[N];
long long sum[N];
int Get1(int l,int r)
{
if(l > r) return 0;
return r - l + 1;
}
long long Get2(int l,int r)
{
return sum[r] - sum[l - 1];
}
int main(void)
{
scanf("%d%d%d",&n,&q,&k);
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
}
for(int i = 1; i <= n; i++)
{
if(i == 1)
{
b[i] = Get1(1,a[i + 1] - 1);
}
else
{
if(i == n)
{
b[i] = Get1(a[i - 1] + 1,k);
}
else b[i] = Get1(a[i - 1] + 1,a[i + 1] - 1);
}
--b[i];
// printf("b[%d] = %d\n",i,b[i]);
}
for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + b[i];
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
if(l == r)
{
printf("%d\n",k - 1);
continue;
}
if(l + 1 == r)
{
long long ans = Get1(1,a[r] - 1) - 1 + Get1(a[l] + 1,k) - 1;
printf("%lld\n",ans);
continue;
}
long long ans = Get2(l + 1,r - 1);
ans += Get1(1,a[l + 1] - 1) - 1;
ans += Get1(a[r - 1] + 1,k) - 1;
printf("%lld\n",ans);
}
return 0;
}
C. Floor and Mod
这题有点恶心,虽然只有*1700。
考虑固定住\(b\)。
很容易想到\(\left \lfloor \frac{a}{b} \right \rfloor\)的答案是一块一块的,然后就会联想到:
对于\(a \in [1,b),\left \lfloor \frac{a}{b} \right \rfloor = 0\)
对于\(a \in [b,2b),\left \lfloor \frac{a}{b} \right \rfloor = 1\)
对于\(a \in [2b,3b),\left \lfloor \frac{a}{b} \right \rfloor = 2\)
\(\cdots\)
对于\(a \in [(k - 1)b,kb),\left \lfloor \frac{a}{b} \right \rfloor = k - 1 \space (k \le b)\)
然后我们会发现,除了第一组,其它每一组对答案都有\(1\)的贡献。
对于第\(k\)块,对答案有贡献(即\(\left \lfloor \frac{a}{b} \right \rfloor = a \bmod b\))的\(a_k = (k - 1)b + k - 1 = (k - 1)(b + 1)\)。同时\(a\)还得要满足\(a \le x\)的性质,而我们的目标,就是找到最大的这个\(k\),然后对于每一个\(b\),求出其最大值\(k\),其对答案贡献为\(k - 1\)。
考虑对于每个\(b\)如何求出\(k\)最大值。
根据上面的东西列不等式:
然后取个整即可。不过要和\(b\)取\(\min\)。
通过分析,我们发现我们要求
单次询问复杂度\(\mathcal{O}(b)\),然而\(b \le 10^9\)
我们发现了下取整符号,考虑分块,但是得先把\(\min\)去掉。
列不等式
对于\([1,\sqrt{x + 1}]\)直接等差数列求和,对于\([\sqrt{x + 1} + 1,y]\)使用数论分块。
# include <bits/stdc++.h>
using namespace std;
int t;
long long x,y;
# define min(x,y) x < y ? x : y
long long solve(void)
{
long long ans = 0;
bool flag = 0;
for(int b = 1; b <= y; b++)
{
ans += min(b - 1,int(x / (b + 1)));
if(b - 1 > x / (b + 1) && !flag)
{
printf("flag = %d\n",b);
flag = 1;
}
}
return ans;
}
long long dc(int l,int r)
{
return (l + r) * (r - l + 1) / 2;
}
long long solve2(void)
{
long long ans = 0;
int SQ = int(sqrt(x + 1));
ans = dc(0,min(SQ - 1,y - 1)); // [1,SQ]
// printf("SQ = %d\n",SQ
for(int l = SQ + 2,r = 0; l <= y + 1; l = r + 1)
{
int s = x / l;
if(!s) break;
r = min(x / s,y + 1);
ans += (r - l + 1) * s;
}
return ans;
}
int main(void)
{
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld",&x,&y);
printf("%lld\n",solve2());
}
return 0;
}
D. Multiples and Power Differences
构造题。
若\(i + j\)为偶,填\(720720\)。
若\(i + j\)为奇,填\(720720 + a_{i,j}^4\)
E. Move and Swap
# include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int t;
int n;
long long a[N],dp[N];
vector <int> g[N],G[N];
int f[N],dep[N];
const long long inf = 1e10;
// # define max(a,b) a > b ? a : b
int d;
void dfs(int x,int fa)
{
G[dep[x]].push_back(x);
d = max(d,dep[x]);
for(int i = 0; i < (int)g[x].size(); i++)
{
int v = g[x][i];
if(v != fa)
{
f[v] = x;
dep[v] = dep[x] + 1;
dfs(v,x);
}
}
return;
}
int main(void)
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i = 1; i <= n; i++)
{
dep[i] = 0;
f[i] = 0;
G[i].clear();
g[i].clear();
dp[i] = 0;
}
for(int i = 2; i <= n; i++)
{
int v;
scanf("%d",&v);
g[i].push_back(v);
g[v].push_back(i);
}
for(int i = 2; i <= n; i++)
{
scanf("%lld",&a[i]);
}
dep[1] = 0;
dfs(1,0);
// printf("d = %d\n",d);
// // dp[0] = 0;
// for(int i = 1; i <= n; i++)
// {
// printf("dep[%d] = %d\n",i,dep[i]);
// }
// putchar('\n');
for(int i = 1; i <= d; i++)
{
long long Max = -inf,Min = inf,Max1 = -inf,Max2 = -inf;
for(int j = 0; j < (int)G[i].size(); j++)
{
int v = G[i][j];
Max = max(Max,a[v]);
Min = min(Min,a[v]);
Max1 = max(Max1,a[v] + dp[f[v]]);
Max2 = max(Max2,dp[f[v]] - a[v]);
}
// printf("i = %d,Max = %lld,Min = %lld,Max1 = %lld,Max2 = %lld\n",i,Max,Min,Max1,Max2);
for(int j = 0; j < (int)G[i].size(); j++)
{
int v = G[i][j];
dp[v] = max(abs(Min - a[v]),abs(Max - a[v])) + dp[f[v]];
dp[v] = max(dp[v],max(Max1 - a[v],Max2 + a[v]));
}
}
long long ans = 0;
for(int i = 1; i <= n; i++)
{
ans = max(ans,dp[i]);
}
printf("%lld\n",ans);
}
return 0;
}