2019江西省赛
Solved | A | B | C | D | E | F | G | H | I | J | K |
---|---|---|---|---|---|---|---|---|---|---|---|
11/11 | Ø | Ø | Ø | O | Ø | O | O | O | O | O | O |
A - Cotree HDU - 6567(树的重心性质)
题意: 给你两棵树,添加一条边变成一棵树,使得任意两点距离和最小
∑ i = 1 n ∑ j = i + 1 n d i s ( i , j ) \sum_{i=1}^{n}\sum_{j=i+1}^{n}dis(i,j) ∑i=1n∑j=i+1ndis(i,j)
思路: 我们需要在两棵树各寻找一个点,然后添加一条边,其实这两个点就是在各自树上其他点到它本身距离之和最小的点,也就是树的重心,找到重心后连边,每条边的贡献之和就是答案
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=1e5+5;
vector<int>G[N];
bool vis[N];
int root,n;
ll sz[N],sum[N],tmpsum,ans;
void dfsOne(int u,int fa)
{
sz[u]=1;
vis[u]=true;
for(int v: G[u])
{
if(v==fa)
continue;
dfsOne(v,u);
sz[u]+=sz[v];
sum[u]+=sum[v]+sz[v];
}
}
void dfsTwo(int u,int fa)
{
if(tmpsum>sum[u])
{
root=u;
tmpsum=sum[u];
}
for(int v: G[u])
{
if(v==fa)
continue;
ll tmp=sum[u]-sum[v]-sz[v];
sum[v]+=tmp+sz[u]-sz[v];
sz[v]+=sz[u]-sz[v];
dfsTwo(v,u);
}
}
void dfs(int u,int fa)
{
sz[u]=1;
for(int v: G[u])
{
if(v==fa)
continue;
dfs(v,u);
sz[u]+=sz[v];
ans+=(n-sz[v])*sz[v];
}
}
int main()
{
//std::ios::sync_with_stdio(0);
#ifdef Mizp
freopen("in.txt","r",stdin);
#endif
scanf("%d",&n);
for(int i=1;i<=n-2;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
int rootOne=1,rootTwo=1;
root=1;
dfsOne(1,0);
tmpsum=sum[1];
dfsTwo(1,0);
rootOne=root;
while(vis[rootTwo])
rootTwo++;
root=rootTwo;
dfsOne(rootTwo,0);
tmpsum=sum[rootTwo];
dfsTwo(rootTwo,0);
rootTwo=root;
G[rootTwo].push_back(rootOne);
G[rootOne].push_back(rootTwo);
ans=0;
dfs(1,0);
printf("%lld\n",ans);
return 0;
}
B - Math HDU - 6568(概率dp)
题意: Avin要带着机器人从0走到L,走路速度为每秒一格并且只会在整数格停下,他走路按照以下规则:
1.如果Avin没有弄丢机器人,则有p的概率弄丢机器人
2.如果Avin已经弄丢了机器人,则有q的概率发现,特别的,当他到达终点却没有机器人时,会立刻发现
3.如果Avin发现他弄丢了机器人,则会一直往左走直到遇见机器人,否则他会向右走一格
问Avin从0走到L的期望花费距离是多少?
思路: dp[i]表示由i到i+1的期望步数
最后 d p [ i ] = ( 1 − p ) ∗ 1 + p ∗ ( d p [ i ] + ( 1 − q ) ( L − i ) ∗ ( L − i ) ∗ 2 + ∑ x = 0 L − i − 1 q ∗ ( 1 − q ) x ∗ 2 ∗ x ) dp[i]=(1-p)*1+p*(dp[i]+(1-q)^{(L-i)}*(L-i)*2+\sum_{x=0}^{L-i-1}q*(1-q)^{x}*2*x) dp[i]=(1−p)∗1+p∗(dp[i]+(1−q)(L−i)∗(L−i)∗2+∑x=0L−i−1q∗(1−q)x∗2∗x)
化简得 d p [ i ] = 1 + 2 ∗ p ∗ ( ( 1 − q ) L − i ( L − i ) + q ∗ ∑ x = 0 L − i − 1 ( 1 − q ) x ∗ x ) 1 − p dp[i]=1+\frac{2*p*((1-q)^{L-i}(L-i)+q*\sum_{x=0}^{L-i-1}(1-q)^x*x)}{1-p} dp[i]=1+1−p2∗p∗((1−q)L−i(L−i)+q∗∑x=0L−i−1(1−q)x∗x)
a n s = ∑ i = 0 L − 1 d p [ i ] ans=\sum_{i=0}^{L-1}dp[i] ans=∑i=0L−1dp[i]
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=1e5+5;
double dp[N],tmp[N];
double b[N];
int main(){
//freopen("in.txt","r",stdin);
//std::ios::sync_with_stdio(0);
int l;
double p,q;
while(~scanf("%d%lf%lf",&l,&p,&q)){
double t=1.0;
for(int i=1;i<l;i++){
t*=(1-q);
tmp[i]=tmp[i-1]+t*i*q;
//cout<
}
b[0]=1.0;
for(int i=1;i<=l;i++){
b[i]=b[i-1]*(1-q);
}
for(int i=0;i<l;i++){
dp[i]=dp[i-1]+1+2*p*(b[l-i]*(l-i)+tmp[l-i-1])/(1-p);
}
printf("%.6f\n",dp[l-1]);
}
return 0;
}
C - Trap HDU - 6569
题意: 给你n条边选取四条边组成一个等腰梯形且四条边gcd为1,问有多少种组合方案
思路: 容斥,我们可以先不考虑gcd为1的情况,算出总方案数后,利用莫比乌斯函数作为容斥系数进行容斥
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=2e5+5;
const int M=1e4+5;
int prime[M],check[M],mu[M],tot;
vector<vector<int>>fac,vec;
int cnt[M],a[M],n;
void init()
{
tot=0;
memset(check,0,sizeof check);
mu[1]=1;
fac.clear();
fac.resize(M);
for(int i=2;i<M;i++)
{
if(!check[i])
{
prime[++tot]=i;
mu[i]=-1;
}
for(int j=1;j<=tot;j++)
{
if(1ll*i*prime[j]>=M)
break;
check[i*prime[j]]=1;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}else {
mu[i*prime[j]]=-mu[i];
}
}
}
for(int i=1;i<M;i++)
{
for(int j=i;j<M;j+=i)
{
fac[j].push_back(i);
}
}
}
int main()
{
// freopen("in.txt","r",stdin);
//std::ios::sync_with_stdio(0);
init();
while(scanf("%d",&n)!=EOF)
{
vec.clear();
vec.resize(M);
memset(cnt,0,sizeof cnt);
int maxx=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
maxx=max(a[i],maxx);
cnt[a[i]]++;
for(int j: fac[a[i]])
{
vec[j].push_back(a[i]);
}
}
ll ans=0;
for(int i=1;i<=maxx;i++)
{
if(!vec[i].size()||mu[i]==0)
continue;
ll tmp=0;
sort(vec[i].begin(),vec[i].end());
vec[i].erase(unique(vec[i].begin(),vec[i].end()),vec[i].end());
int sz=vec[i].size();
for(int it: vec[i]) //topline
{
int l=0,r=0;
while(l<sz&&vec[i][l]<it+1)
l++;
for(int it1: vec[i]) // yao
{
if(it1!=it && cnt[it1]>=2)
{
while(r<sz&&vec[i][r]<it+it1*2)
r++;
r--;
if(l<sz&&r<sz&&r-l>=0)
{
tmp+=r-l+1;
if(vec[i][l]<=it1&&vec[i][r]>=it1&&cnt[it1]<3)
tmp--;
}
}
else if(it1==it && cnt[it]>=3)
{
while(r<sz&&vec[i][r]<it+it1*2)
r++;
r--;
if(l<sz&&r<sz&&r-l>=0)
tmp+=r-l+1;
}
}
}
ans+=tmp*mu[i];
}
printf("%lld\n",ans);
}
return 0;
}
D - Wave HDU - 6570(签到题)
略
E - Packing HDU - 6571
题意: 给你n件物品的到达时间与所到达窗口,与m个窗口的容量,将窗口的物品移走1件需要1秒,若窗口积压的物品超过容量,则需要支付超过部分的代价,每件代价为1,问将所有物品搬离窗口至少需要付出多少代价
思路: 待补
F - String HDU - 6572(签到题)
略
G - Traffic HDU - 6573(签到题)
略
H - Rng HDU - 6574
题意: 考虑随机选择一个区间的过程:
先从[1,n]随机取一个点r,接着在[1,r]随机取一个点l
问随机选择两个区间,它们相交的概率?
思路: 此题在训练时,我是打表找到规律的
然后正确做法参考此位大佬题解
#include
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
long long n;
ll qpow(ll a, ll x)
{
ll ret = 1;
while(x)
{
if(x%2) ret = (ret*a)%mod;
a = (a*a)%mod;
x /= 2;
}
return ret;
}
int main()
{
while(scanf("%lld", &n)!= EOF)
{
long long one_two = qpow(2, mod-2);
long long a = qpow(2*n, mod-2);
printf("%lld\n", (one_two + a)%mod);
}
}
I - Budget HDU - 6575(签到题)*
略
J - Worker HDU - 6576(签到题)
略
K - Class HDU - 6577(签到题)
略