2022 HDU多校6
Maex
Problem
给定一个大小为的树,每个节点有一个权值,并且保证不存在两个点的点权相同,定义。现在你可以给这些点赋予点权,使得最大,请求出这个值。
Solve
hit1
:保证不存在两个点的点权相同
根据这个,考虑一个节点的不为,当且仅当它的子树里面出现过点权为的节点,而这个点权为的节点当且仅有一个,然后一直往这个子树里面找,发现不为的点一定形成一条链,并且这条链上的节点的就是这个节点子树的大小,因为考虑这个子树中不存在权值点的那些链,发现他们的贡献一定是,那我们直接按照顺序赋值可以最优,所以直接一直往下搜索找到最大值即可
Code
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin>>T;
while(T--){
int n;
cin>>n;
vector<int>sz(n+1);
vector<vector<int>>E(n+1);
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
E[u].push_back(v);
E[v].push_back(u);
}
auto dfs1=[&](auto self,int u,int fa)->void{
sz[u]=1;
for(auto v:E[u]){
if(v==fa) continue;
self(self,v,u);
sz[u]+=sz[v];
}
sort(E[u].begin(),E[u].end(),[&](int i,int j){return sz[i]>sz[j];});
};
dfs1(dfs1,1,1);
ll ans=0;
auto dfs2=[&](auto self,int u,int fa,ll w)->void{
ans=max(ans,w);
for(auto v:E[u]){
if(v==fa) continue;
self(self,v,u,w+sz[v]);
}
};
dfs2(dfs2,1,1,n);
cout<<ans<<'\n';
}
}
Shinobu loves trip(数论、卡常)
Problem
有个任务,每个任务可以用来表示,现在有个询问,每次询问给定一个数,问有多少个任务满足,,其中题目给定。
,
Solve
问题转变就是有多个任务,满足,使得,变形一下就是。所以可以求出每个的值,然后记录可以变成这个值的最小的天数,如果一个任务的大于这个最小的,那么就可以达到。
Code
#include <iostream>
#include <unordered_map>
#define ll long long
using namespace std;
const int N=10005;
const int D=200005;
int P,a,n,q;
int s[N],d[N],apw[D],inv[N];
inline int power(int x,int y){
int res=1;
while(y){
if(y&1) res=(ll)res*x%P;
x=(ll)x*x%P;
y>>=1;
}
return res;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin>>T;
while(T--){
cin>>P>>a>>n>>q;
int mx=0;
for(int i=1;i<=n;i++){
cin>>s[i]>>d[i];
mx=max(mx,d[i]);
inv[i]=power(s[i],P-2);
}
unordered_map<int,int>hs;
apw[0]=1;
hs[apw[0]]=0;
int limit=min(mx,P-2);
for(int i=1;i<=limit;i++){
apw[i]=(ll)apw[i-1]*a%P;
if(hs.find(apw[i])==hs.end()){
hs[apw[i]]=i;
}
}
int ans;
while(q--){
int x;
cin>>x;
ans=0;
if(x==0){
for(int i=1;i<=n;i++){
if(s[i]==0) ans++;
}
cout<<ans<<'\n';
continue;
}
for(int i=1;i<=n;i++){
if(s[i]==0) continue;
int t=(ll)x*inv[i]%P;
if(hs.count(t) && hs[t]<=d[i]) ans++;
}
cout<<ans<<'\n';
}
}
return 0;
}
Map(计算几何、巴拿赫不动点)
Problem
给定二维平面中两个相似矩形,保证小矩形包含在大矩形中,问不动点坐标(巴拿赫不动点)
Solve
我们先把一个地图看做一个直角坐标系,在这个坐标系里面表示不动点点,取垂直的两条边作基向量即可,可以得到两个等式
然后可以得到
作差可以得到
然后对应分量相等得到两个方程组解和即可
Code
乘法运算的时候不要用double
,因为这个一直T
#include <bits/stdc++.h>
#define ll long long
using namespace std;
struct Point{
int x,y;
Point operator + (const Point&t)const{
return {x+t.x,y+t.y};
}
Point operator - (const Point&t)const{
return {x-t.x,y-t.y};
}
}M[5],m[5];
typedef Point Vector;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout<<fixed<<setprecision(6);
int T;
cin>>T;
while(T--){
for(int i=1;i<=4;i++){
int x,y;
cin>>x>>y;
M[i]={x,y};
}
for(int i=1;i<=4;i++){
int x,y;
cin>>x>>y;
m[i]={x,y};
}
Vector AB=M[2]-M[1],AD=M[4]-M[1];
Vector ab=m[2]-m[1],ad=m[4]-m[1];
Vector Oa=m[1],OA=M[1];
int x1=(AB-ab).x,y1=(AB-ab).y;
int x2=(AD-ad).x,y2=(AD-ad).y;
int x=(Oa-OA).x,y=(Oa-OA).y;
double t1=(x*y2-y*x2)/(double)(x1*y2-x2*y1);
double t2=(x*y1-y*x1)/(double)(x2*y1-x1*y2);
double Px=OA.x+AB.x*t1+AD.x*t2,Py=OA.y+AB.y*t1+AD.y*t2;
cout<<Px<<" "<<Py<<'\n';
}
return 0;
}
Planar graph(图论、最大生成树)
Problem
给定一个平面图。平面图围被若干条边分成若干个平面。把每个平面看做城市,你需要在边上建桥,使得城市之间可以互通。问最少需要建多少个桥,可以使得每个面之间可以相互到达,并且要求建立桥的边的字典序最小。
Solve
建立桥可以看做是断边操作,发现断完边之后就图上是没有环的,变成了一棵树,而要求断开的边字典序要最小,所以按照把边的序号当做边权,求一个最大生成树,把不在树中的边加入答案即可
Code
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
struct edges{
int u,v;
}e[N];
int f[N];
int find(int x){
return f[x]==x?x:f[x]=find(f[x]);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin>>T;
while(T--){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
e[i]={u,v};
}
vector<int>ans;
for(int i=m;i>=1;i--){
int u=e[i].u,v=e[i].v;
int fu=find(u),fv=find(v);
if(fu==fv){
ans.push_back(i);
continue;
}
f[fu]=fv;
}
cout<<ans.size()<<'\n';
reverse(ans.begin(), ans.end());
for(auto x:ans) cout<<x<<" ";
cout<<'\n';
}
}
Find different(数论、群论)
Loop(贪心)
Problem
给定一个长度为的序列,可以进行次操作,每次操作可以选择一个区间,然后把这个区间的数循环左移位。问最后可以得到的最大字典序的序列是多少
Solve
字典序最大,就是前面的数字尽可能大,降序尽可能多。操作可以看做每次可以把一个前面的数放在后面的任意位置,显然,我们要尽可能把前面小的数字放到后面。比如如果存在,那么可能放到后面会更好,然后继续检查,而我们要求字典序最大,所以从前面往后检查是更优的,所以每次可以放就一定放到后面并且消耗一次操作,知道无法操作就停止检查,这时我们可以得到一个保留序列和删除序列,然后把删除序列中的数大贪心地插入到保留序列里面即可
Code
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin>>T;
while(T--){
int n,k;
cin>>n>>k;
vector<int>a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
vector<int>rem;
priority_queue<int> del;
for(int i=1;i<=n;i++){
while(rem.size() && rem.back()<a[i] &&k){
del.push(rem.back());
rem.pop_back();
k--;
}
rem.push_back(a[i]);
}
vector<int>b;
rem.push_back(-1e9);
del.push(-1e9);
int id=0;
while(int(b.size())<n){
if(rem[id]>=del.top()) b.push_back(rem[id++]);
else b.push_back(del.top()),del.pop();
}
for(int i=0;i<n;i++){
cout<<b[i];
if(i!=n-1) cout<<" ";
else cout<<"\n";
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?