D - Line++
题意:
给n,x,y
表示存在一个n个顶点的无向图图,对于每一对(i,i+1)都存在边,那么整个图就是一条链
现在顶点x和顶点y之间添加了一条边,
所有边的长度都是1
现在问:
有多少点对(a,b),满足a到b的最短距离为1,输出点对数量,
有多少点对(a,b),满足a到b的最短距离为2,输出点对数量,
有多少点对(a,b),满足a到b的最短距离为3,输出点对数量,
…
有多少点对(a,b),满足a到b的最短距离为n-1,输出点对数量,
数据范围:n<=1e3,1<=x<y<=n
解法:
观察到n只有1e3,因此O(n2)枚举点对,记录最短距离出现的次数即可
求i到j最短距离的时候,计算不走x-y的距离,和走x-y的距离,取min就是最短距离了
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=2e5+5;
int mark[maxm];
signed main(){
int n,x,y;
cin>>n>>x>>y;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int a=abs(i-j);//按原来的路走
int b=abs(x-i)+abs(y-j)+1;//走x-y
int d=min(a,b);
mark[d]++;
}
}
for(int i=1;i<=n-1;i++)cout<<mark[i]<<endl;
return 0;
}
E - Red and Green Apples
题意:
给定x,y,A,B,C
分别表示你现在要吃x个红苹果,y个绿苹果,
你现在有A个红苹果,B个苹果,C个无色苹果
然后给长度为A的数组a,a(i)表示第i个红苹果的权值
然后给长度为B的数组b,b(i)表示第i个绿苹果的权值
然后给长度为C的数组c,c(i)表示第i个无色苹果的权值
吃无色苹果之前可以把他先染色为红色或者绿色,
现在问你吃x个红苹果,y个绿苹果之后的最大权值和
数据范围:x,y,A,B,C<=1e5,a(i),b(i),c(i)<=1e9
解法:
容易想到排序之后优先取最大。
容易进入的误区是吃无色苹果之前要把它先染成某一种颜色,然后就不知道怎么处理了。
其实不用管染成哪种色,多开一个变量记录选择的无色苹果的个数
假设选择xx个红色,yy个绿色,zz个无色,当xx+yy+zz==x+y的时候退出即可。
不需要确定每个选择的无色苹果染成哪种颜色。
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=3e5+5;
struct Node{
int v;
int id;
}e[maxm];
signed main(){
int x,y,A,B,C;
cin>>x>>y>>A>>B>>C;
int n=0;
for(int i=1;i<=A;i++)cin>>e[++n].v,e[n].id=1;
for(int i=1;i<=B;i++)cin>>e[++n].v,e[n].id=2;
for(int i=1;i<=C;i++)cin>>e[++n].v,e[n].id=3;
sort(e+1,e+1+n,[](Node a,Node b){return a.v>b.v;});
int xx=0,yy=0,zz=0;
int ans=0;
for(int i=1;i<=n;i++){
if(e[i].id==1){
if(xx<x)xx++,ans+=e[i].v;
}else if(e[i].id==2){
if(yy<y)yy++,ans+=e[i].v;
}else{
if(xx+yy+zz<x+y)zz++,ans+=e[i].v;
}
if(xx+yy+zz==x+y)break;
}
cout<<ans<<endl;
return 0;
}
F - Distributing Integers
题意:
给一颗n个顶点的树
先选择一个点作为起始顶点,填上数字1,
然后任选一个与有数字点相邻的无数字点,填上2,
然后任选一个与有数字点相邻的无数字点,填上3,
重复操作知道填完。
现在问你1到n的每个顶点轮流作为起始点,分别有多少种填数字的可能,答案对1e9+7取模。
解法:
这道题其实就是计算以每个顶点作为根的拓扑序列数。
对于有根树,拓扑序列数为:
那么这题就是对于每个顶点,计算所有子树大小的乘积。
树形dp换根即可。
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=2e5+5;
const int mod=1e9+7;
vector<int>g[maxm];
int mul[maxm];
int sz[maxm];
int n;
int ppow(int a,int b,int mod){
int ans=1%mod;a%=mod;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void dfs1(int x,int fa){
sz[x]=1;
for(int v:g[x]){
if(v==fa)continue;
dfs1(v,x);
sz[x]+=sz[v];
mul[x]=mul[x]*mul[v]%mod;
}
mul[x]=mul[x]*sz[x]%mod;
}
void dfs2(int x,int fa){
for(int v:g[x]){
if(v==fa)continue;
//mul[x]是正确的
int pre=mul[x]*ppow(n,mod-2,mod)%mod*ppow(mul[v],mod-2,mod)%mod*(n-sz[v])%mod;
mul[v]=mul[v]*ppow(sz[v],mod-2,mod)%mod*pre%mod*n%mod;
dfs2(v,x);
}
}
signed main(){
cin>>n;
for(int i=1;i<n;i++){
int a,b;
cin>>a>>b;
g[a].push_back(b);
g[b].push_back(a);
}
for(int i=1;i<=n;i++)mul[i]=1;
dfs1(1,-1);
dfs2(1,-1);
int nn=1;
for(int i=1;i<=n;i++){//阶乘
nn=nn*i%mod;
}
for(int i=1;i<=n;i++){
cout<<nn*ppow(mul[i],mod-2,mod)%mod<<endl;
}
return 0;
}