总的思路是:
由于两棵树分别有多少个节点我们不知道,所以我们要用并查集去获得根节点(注意,该根节点不是最优解)的同时,获得该树的个数n1,n2。
然后开始考虑两边树的重心。---知道了最优的两个根节点位置。
将树的根节点相连,求:在一个树,一个点到另个点的距离。 就是该节点个数*其余节点个数----至于为什么---要问尤老师了。
- 求和
- 最大的和
求和
#include<stdio.h>
#include<queue>
#include<iostream>
#include<algorithm>
#include<vector>
const long long maxn=1e8+10;
using namespace std;
long long f[maxn];
/*
1.构造----2.排序变成区间的形式------3.求得区间长度即个数-------4.相乘 相加。
打表。前缀和。 10的9次必须longlong了 遍历一遍就O(n)了,不行。所以思路:自己构造,写出所有4 和 7的组合。
然后根据经验,类似这种题型的都是根据区间来划分,操作的。
所以代码核心:res += S[i] * max(0ll, (min(r, b) - max(l, a) + 1));
关键1:如何构造自己构造出所有4 和 7的组合。----------递归。
*/
vector<long long> v;
void make_number(int u,long long n)//u记录位数,n为构造大小
{
v.push_back(n);
if(u>=10) return ;
make_number(u+1,n*10+4);
make_number(u+1,n*10+7);
}
int main()
{
make_number(0,0);
sort(v.begin(),v.end());
long long l,r;
cin>>l>>r;
long long res=0;
for(int i=1;i<v.size();i++)
{
long long l1=v[i-1]+1,r1=v[i];
res+=v[i]*max(0ll,(min(r,r1)-max(l,l1)+1));//右端点的最小值-左端点的最大值+1,交集不存在也不能是负数,所以为0;
//知识点 max min 两个类型一致才能比较,int 和 long long 也不能比较。
}
cout<<res<<endl;
system("pause");
return 0;
}
3493. 最大的和
题目大意:告诉你一个数组a(整数),又告诉一个数组标志b初始时刻那些可用,那些不可用(0,不可用,1,可用。)。给你个限定技,在数组a中可以使连续k的的一段区间变成1.
问:求最大的和是多少?
题目
思路:前缀和。或者滑动窗口。
能拿的我们全部拿。 剩下的不能拿的,我们可以想像成一个容器。没次增加,如果容器满了,后面的就得删除。
#include<iostream>
using namespace std;
const int maxn=1e6+10;
/*
一连串的和。求相加----前缀和。
另一种是滚动窗口。
ac了,但还是要好好思考他的关键点。分析他的思路。学习他的技巧。
1.分析为什么用long long
*/
long long s[maxn],m[maxn];
long long max(long long a,long long b)
{
if(a>b) return a;
return b;
}
int main()
{
int x,y,k;
cin>>x>>k;
for(int i=1;i<=x;i++)
{
cin>>s[i];
}
long long sum=0;
for(int i=1;i<=x;i++)
{
cin>>m[i];
if(m[i]!=0) sum=sum+s[i];//能拿的我们全部拿。
}
long long v=0,u=0;
for(int i=1;i<=x;i++)
{
if(!m[i]) u=u+s[i];
if(i>k&&!m[i-k]) u=u-s[i-k];//没次增加,如果容器满了,后面的就得删除
v=max(v,u);//暴力枚举,看看哪种组合最大。
}
cout<<sum+v<<endl;
return 0;
}