2019江西省赛

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=1nj=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的期望步数

  1. 如果在i点不丢失机器人 则为 ( 1 − p ) ∗ 1 (1-p)*1 (1p)1
  2. 如果在i点丢失机器人,分两种情况
    1)到达终点L都未发现,则 p ∗ ( 1 − q ) ( L − i ) ∗ ( L − i ) ∗ 2 p*(1-q)^{(L-i)}*(L-i)*2 p(1q)(Li)(Li)2
    2)在到达终点L之前发现,则 p ∗ ∑ x = 0 L − i − 1 q ∗ ( 1 − q ) x ∗ 2 ∗ x p*\sum_{x=0}^{L-i-1}q*(1-q)^{x}*2*x px=0Li1q(1q)x2x

最后 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]=(1p)1+p(dp[i]+(1q)(Li)(Li)2+x=0Li1q(1q)x2x)
化简得 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+1p2p((1q)Li(Li)+qx=0Li1(1q)xx)
a n s = ∑ i = 0 L − 1 d p [ i ] ans=\sum_{i=0}^{L-1}dp[i] ans=i=0L1dp[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
问随机选择两个区间,它们相交的概率?
思路: 此题在训练时,我是打表找到规律的
然后正确做法参考此位大佬题解
2019江西省赛_第1张图片

#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(签到题)

你可能感兴趣的:(套题)