掉分md
D: 数学构造
E : 简单思维
F:图论,树 ,树的中心,维护对于树上每个点,到该点的最远距离是多少,板子
G:数学,计数
F:
题意:题意:树的收益是root(初始root=1)到最远的点的距离,更改相邻一个点成为root的要付出代价是c。 求最大利润
分析:只需维护出树上每个点与 距离最远的点的距离是多少。参考acwing树的中心,以及前不久div2 的一个D题也是这么做。
每个点当做root的收益 就是最远的点到自己的距离,减去成为根节点的代价(深度-1) 取最大值即可。
板子:求对于树上每一个点,最远的点到自己的距离是多少 max(d1[i],up[i])
- //dfs1
- //dfs2
- //维护出每一个点的深度
- //维护出每一个点到最远的点的距离
- //树的中心
- int deg[N]; //深度
- int d1[N],d2[N],p1[N],p2[N],up[N];
- void dfs1(int u,int fa)
- {
- deg[u]=deg[fa]+1;
- for(int i=h[u];i!=-1;i=ne[i])
- {
- int j=e[i];
- if(j==fa)
- continue;
- dfs1(j,u);
- if(1+d1[j]>=d1[u])
- {
- d2[u]=d1[u];
- p2[u]=p1[u];
- d1[u]=1+d1[j];
- p1[u]=j;
- }
- else if(1+d1[j]>d2[u])
- {
- d2[u]=1+d1[j];
- p2[u]=j;
- }
- }
- }
- void dfs2(int u,int fa)
- {
- for(int i=h[u];i!=-1;i=ne[i])
- {
- int j=e[i];
- if(j==fa)
- continue;
- if(p1[u]==j)
- up[j]=1+max(up[u],d2[u]);
- else
- up[j]=1+max(up[u],d1[u]);
- dfs2(j,u);
- }
- }
- //dfs求代价
- dfs1(1,0);
- dfs2(1,0);
- ll res=0;
- for(int i=1;i<=n;i++) //枚举这个点成为root的收益
- res=max(res, (ll)k*max(up[i],d1[i])-((ll)deg[i]-1)*c );
- cout<<res<<endl;
G
简单版本 G1 ai<=1e6
困难版本 G2 ai<=1e9
问有多少个三元组( i,j,k ) (允许相等)满足 存在b ,使得a[j]=a[i]*b, a[k]=a[j]*b
Easy verson:
遍历i, 遍历b 。直接计数 cnt[a[i]] *cnt[a[i]*b]*cnt[a[i]*b*b]即可
用数组计数,每次清空。 同时离散化去重应该会快一些
- sort(a.begin(),a.end());
- a.erase(unique(a.begin(),a.end()) ,a.end());
- int ma=a.back();
- for(int i=0;i<a.size();i++)
- {
- if(cnt[a[i]]>=3)
- res+=(ll)(cnt[a[i]])*(cnt[a[i]]-1)*(cnt[a[i]]-2);
- for(int j=2;;j++) //倍数
- {
- ll t1=(ll)a[i]*j;
- ll t2=(ll)(a[i])*j*j;
- if(t2>ma||t1>ma)
- break;
- else if(cnt[t1]!=0&&cnt[t2]!=0)
- res+=(ll)cnt[a[i]]*cnt[t1]*cnt[t2];
- }
- }
- cout<<res<<endl;
- for(int i=0;i<a.size();i++)
- cnt[a[i]]=0;
- //清空
- }
竟然卡map, unordered_map能过。
G2
困难版本: 区别,a[i]<=1e9,
统计 存在b,使得 a[i]*b=a[j],a[j]*b=a[k], 三元组( I,j,k)的个数
对于a[i]>=1e6的数, 枚举中间的数a[j],以及枚举b, 因为a[k]<=1e9;
所以b最多枚举1000
对于a[i]<=1e6的数,若固定a[i]或者固定a[j]枚举b的话,b的量级==(1e9)/a[i],量级可达很高,时间复杂度不可接受 这时可枚举a[j]的因子,因数分解的时间复杂度为根号a[i],时间复杂度为1000.可接受 总的复杂度为 n* 1000差不多
强调:longlong 的运算速度比int要慢,这题对时间卡的很极限,longlong大概率T掉
代码:服了,T49,再想想
- //枚举中间数a[j] //计数a[j]/b,a[j],a[j]*b;
- //计数
- int ma=a.back();
- for(int i=0;i<a.size();i++)
- {
- if(mp[a[i]]>=3)
- res+=(ll)mp[a[i]]*(mp[a[i]]-1)*(mp[a[i]]-2);
- if(a[i]==1)
- continue;
- if(a[i]<=1e6)
- {
- //质因数分解
- //枚举它的所有因数
- for(int j=1;j<=a[i]/j;j++)
- {
- if(a[i]%j==0)
- {
- if((ll)a[i]/j*a[i]<=ma)
- res+= (ll)mp[j]*mp[a[i]]*mp[a[i]/j*a[i]];
- if(j!=1&&a[i]/j!=j)
- {
- int j1=a[i]/j;
- if((ll)a[i]/j1*a[i]<=ma)
- res+= (ll)mp[j1]*mp[a[i]]*mp[a[i]/j1*a[i]];
- }
- }
- }
- }
- else
- {
- for(int b=2;b<=ma/a[i];b++)
- {
- if(a[i]%b!=0)
- continue;
- if((ll)a[i]*b<=ma)
- res+= (ll)mp[a[i]/b ]*mp[a[i]]*mp[a[i]*b ];
- }
- }
- }
- cout<<res<<endl;
- }