| 题目 | 难度 | 知识点 |
|---|---|---|
| A 小美的排列询问 | ★ | 签到 |
| B 小美走公路 | ★ | 枚举 |
| C 小美的排列构造 | ★ | 构造 |
| D 小美的树上染色 | ★★ | 树形DP |
D题想到了树形DP,但是写wa了,确实不会但理论上是应该要做出来的。
小美的排列询问
#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
int a[N],st[N],n;
int main(void)
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i],st[a[i]]=i;
int x,y; cin>>x>>y;
int temp=abs(st[x]-st[y]);
if(temp==1) puts("Yes");
else puts("No");
return 0;
}
小美走公路
打表找规律,挺容易发现的,算是cf中比较简单和经典的构造题。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
LL n,a[N],x,y;
int main(void)
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
cin>>x>>y;
if(x>y) swap(x,y);
LL ans1=0,ans2=0;
for(int i=x;i<y;i++) ans1+=a[i];
for(int i=1;i<x;i++) ans2+=a[i];
for(int i=y;i<=n;i++) ans2+=a[i];
cout<<min(ans1,ans2);
return 0;
}
小美的排列构造
#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
LL n,a[N],ans=1e9,b[N];
int main(void)
{
cin>>n;
/*for(int i=0;i<n;i++) a[i]=i+1;
do
{
LL minv=1e9,maxv=-1e9;
for(int i=1;i<n;i++)
{
minv=min(minv,a[i]+a[i-1]);
maxv=max(maxv,a[i]+a[i-1]);
}
if(maxv-minv<ans)
{
ans=maxv-minv;
for(int i=0;i<n;i++) b[i]=a[i];
}
}while(next_permutation(a,a+n));
for(int i=0;i<n;i++) cout<<b[i]<<" ";*/
for(int i=0,j=1;i<n;i+=2,j++) a[i]=j;
for(int i=1,j=n;i<n;i+=2,j--) a[i]=j;
for(int i=0;i<n;i++) cout<<a[i]<<" ";
return 0;
}
/*
3
2 1 3
4
1 4 2 3
5
1 5 2 4 3
6
1 6 2 5 3 4
*/
小美的树上染色
#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e5*5+10;
LL w[N],n,dp[N][2];//表示以i为根的子树,j==0表示该点没选,j==1表示该点选了
vector<int>ve[N];
bool check(LL x)
{
LL res=sqrt(x);
while(res*res<x) res++;
while(res*res>x) res--;
return res*res==x;
}
void dfs(int u,int fa)
{
dp[u][0]=0,dp[u][1]=0;
LL sum=0;
for(int i=0;i<ve[u].size();i++)//该点没有染色,那么其子节点可以染色或者不然
{
int j=ve[u][i];
if(j==fa) continue;
dfs(j,u);
sum+=max(dp[j][1],dp[j][0]);
}
dp[u][0]=sum;
for(int i=0;i<ve[u].size();i++)//尝试该点染色,那个以为着其子节点有一个需要一定不能染色。
{
int j=ve[u][i];
if(j==fa) continue;
if(check(w[u]*w[j]))//选中该点和u进染色了
dp[u][1]=max(dp[u][1],sum-max(dp[j][0],dp[j][1])+dp[j][0]+2);
//总的-减去该子树的贡献+该子树不染色的贡献+该点和u染色的2个。
}
}
int main(void)
{
cin>>n;
for(int i=1;i<=n;i++) cin>>w[i];
for(int i=1;i<=n-1;i++)
{
int a,b; cin>>a>>b;
ve[a].push_back(b);
ve[b].push_back(a);
}
dfs(1,-1);
cout<<max(dp[1][0],dp[1][1]);
return 0;
}