【牛客算法周周练1】题解A/C/E
A 前缀和
一个数移到左边所减少的量= 增加的量为
总的减少量
维护前缀和,枚举下标从k~n-1,找出最少的减少量delta即可
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+5;
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n;scanf("%d",&n);
int k;scanf("%d",&k);
int nums[maxn];
ll sum[maxn]={0};
unsigned ll ans=0;
for(int i=1;i<=n;++i){
scanf("%d",&nums[i-1]);
ans+=i*nums[i-1];
sum[i]=sum[i-1]+nums[i-1];
}
ll delta = 9223372036854775807;
for(int i=n-1;i>=k;--i){
ll dd = nums[i]*k-sum[i]+sum[i-k];
delta=min(delta,dd);
}
printf("%lld\n",ans-delta);
}
}C 树上距离
求树上两个节点的距离有个性质:
这道题我们求出B 到 C,C到 1的距离和 dis1
求出A 到 1的距离 dis2
如果 肯定抓不到
如果 肯定抓的到
如果 时且
则他们俩最终会在1相遇,抓不到,其他情况老师可以去
守株待兔
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define LONGLONGMIN -922337203685477580
const int maxn = 2e5 + 10;
#define MAXN 200010
int p[MAXN], h[MAXN], ne[MAXN];
int num = 0;
int dep[MAXN / 2], f[MAXN / 2][21];
int MAXDEPTH;
//加边
void addEdge(int from, int to)
{
p[++num] = to;
ne[num] = h[from];
h[from] = num;
p[++num] = from;
ne[num] = h[to];
h[to] = num;
}
// 预处理深度和倍增
void dfs(int u, int father)
{
dep[u] = dep[father] + 1;
for (int i = 1; (1 << i) <= dep[u]; ++i) {
f[u][i] = f[f[u][i - 1]][i - 1];
}
for (int i = h[u]; i; i = ne[i])if (p[i] != father) {
f[p[i]][0] = u;
dfs(p[i], u);
}
}
// 求LCA
int LCA(int u, int v){
if(dep[u] > dep[v]) swap(u, v);
int hu = dep[u], hv = dep[v];
for(int det = hv - hu, i = 0; det; det >>= 1, i++){
if(det & 1){
v = f[v][i];
}
}
if(u == v){
return u;
}
for(int i = MAXDEPTH - 1; i >= 0; i--){
if(f[u][i] == f[v][i]) continue;
u = f[u][i];
v = f[v][i];
}
return f[u][0];
}
void init()
{
MAXDEPTH = 20;
num = 0;
memset(f, 0, sizeof(f));
memset(h, 0, sizeof(h));
}
int main()
{
int t;
cin >> t;
while (t--) {
init();
int n, q;
cin >> n >> q;
for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
addEdge(u, v);
}
dep[0]=-1;
dfs(1, 0);
while (q--) {
int a, b, c;
cin >> a >> b >> c;
if (b == c && b == 1) {
cout << "NO\n";
continue;
}
int dis1 = dep[b] + dep[c] - 2 * dep[LCA(b, c)] + dep[c]; // B -> C的距离+ C -> 1的距离dep[c]
int dis2 = dep[a];
// cout<<dis1<<" " <<dis2<<" "<<LCA(b, c)<<endl;
if (dis1 < dis2) {
cout << "NO\n";
} else if (dis1 > dis2) {
cout << "YES\n";
} else {
if (LCA(c, a) == 1)
cout << "NO\n";
else
cout << "YES\n";
}
}
}
return 0;
} E dfs打表预处理
dfs打表预处理出只含有4、7的数字
然后O(n)顺着往下找即可,比如l=48 找到第一个大于l的数为74 则[48,74]这个区间的数的下一个幸运数都为74。参看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e5+5;
ll a[N], k = 0;
void dfs(ll n) //打表
{
if(n>2e10) return;
a[k++] = n;
dfs(n*10+4);
dfs(n*10+7);
}
int main()
{
dfs(0);
sort(a,a+k);
ll l,r;
scanf("%lld %lld",&l,&r);
ll sum = 0, i = l, x = 0;
while(i<=r)
{
while(a[x]<i) x++;
sum += a[x]*(min(r,ax])-i+1);
i = a[x]+1; //下一次从a[x]之后开始
}
printf("%lld\n",sum);
return 0;
} 