今天这个题难度比较低,个人感觉跟2015的NOIP难度近似,第一道题第一眼看上去感觉跟NOIP2013的积木大赛近似,好好看题之后先往二分的方面考虑,发现这道题可以递推,然后自己推出几个来,发现规律,在2的n此方与2的n+1次方之间的数(左闭右开)操作次数都为n+1,然后从这方面入手这道题就特别简单了。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
int a[43],n;
int main()
{
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
a[0]=1;
cin>>n;
if (n==1)cout<<1;else
for (int i=1;i<=30;i++)
{
a[i]=a[i-1]*2;
if (a[i]>n){cout<<i;break;}
}
fclose(stdin);
fclose(stdout);
}
第二题感觉跟昨天的题有点近似,看到了生成树,依然是先考虑并查集来维护,发现和昨天的题近似,也可以用并查集来做。
• 假设左右两块都已联通,当前考虑的边为 (x; y; v),其中左
边最优值为 A,在 a 点取到,右边最优值为 B,在 b 点取
到,左边包含 x 共有 Cx 个点,右边包含 y 共有 Cy 个点。
• 那么,如果使两块联通,最⼤值要么是 A + Cy ∗ v(当我们
选的点在左边,右边所有点的 dist 均为 v),要么是
B + Cx ∗ v(当我们选的点在右边,左边所有点的 dist 均为
v),⽽且除此之外的答案都不比这个更优。
• 所以只要用并查集就好了。记录⼀下当前这个节点的 size,
然后像上面那样合并,最终的联通块的答案就是我们所求。
代码也很好写,本来想写个程序对拍,发现根本懒得动弹= =,然后就好运的A掉了,对于数据好造的题还是要认真的对拍,吸取昨天的教训,这个题对于菊花图最大运行了0.7s,还是比较轻松的过掉了,明天要再接再厉。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int fat[500010],quan[500010],siz[500010],n,m;
struct edge{
int u,v,w;
}e[500000];
int father(int x){if (fat[x]==x)return x;fat[x]=father(fat[x]);return fat[x];}
int unionn(int a,int b,int w)
{
int fa=father(a),fb=father(b);
quan[fa]+=siz[fb]*w;
quan[fb]+=siz[fa]*w;
if(quan[fa]>=quan[fb])
{
siz[fa]+=siz[fb];
fat[fb]=fa;
}
else
{
siz[fb]+=siz[fa];
fat[fa]=fb;
}
}
int cmp(const edge &x,const edge &y){return x.w>y.w;}
int main()
{
freopen("ljqz.in","r",stdin);
freopen("ljqz.out","w",stdout);
cin>>n;
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
fat[i]=i;
siz[i]=1;
}
siz[n]=1;
fat[n]=n;
sort(e+1,e+n,cmp);
for (int i=1;i<n;i++)
{
unionn(e[i].u,e[i].v,e[i].w);
}
cout<<quan[father(1)];
fclose(stdin);
fclose(stdout);
}
t3暴搜题还是等以后来补坑叭,代码有点难写,分阶段暴搜把,剪枝的比较多。