zoukankan      html  css  js  c++  java
  • 2019江苏省赛

    A.Cotreey

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=6567

    题意:有一个$n$个点的树,$n-2$条边,给任意两点间加一条边,问点两两之间的距离之和最小为多少。

    数据范围:$2<=n<=10^5$。

    分析:读完题,学妹:这不是个树形dp+换根嘛?我:喵喵喵???(我不会啊。。

    然后读了一会儿,,,emmmm不是求两个子树重心就好了嘛。

    树的性质有:

    1. 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样。
    2. 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。
    3. 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。
    4. 一棵树最多有两个重心,且相邻。

    所以,连接两棵树的重心,得到的距离和最小。

    求解距离和的时候,考虑每条边的贡献即可。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn=1e5+10;
     5 vector<int> mp[maxn];
     6 int mi1,mi2,id1,id2,num1,num2;
     7 int dp[maxn],vis[maxn],n;
     8 ll num[maxn];
     9 ll ans;
    10 void dfs(int x,int fa){
    11     vis[x]=1;
    12     for (int i=0;i<mp[x].size();i++){
    13         if (mp[x][i]==fa) continue;
    14         dfs(mp[x][i],x);
    15     }
    16 }
    17 void dfs1(int x,int fa){
    18     dp[x]=1;
    19     int mx=0;
    20     for (int i=0;i<mp[x].size();i++){
    21         if (mp[x][i]==fa) continue;
    22         dfs1(mp[x][i],x);
    23         dp[x]+=dp[mp[x][i]];
    24         mx=max(mx,dp[mp[x][i]]); 
    25     }
    26     mx=max(mx,num1-dp[x]);
    27     if (mx<mi1){
    28         mi1=mx;
    29         id1=x;
    30     }
    31 }
    32 void dfs2(int x,int fa){
    33     dp[x]=1; vis[x]=1;
    34     int mx=0;
    35     for (int i=0;i<mp[x].size();i++){
    36         if (mp[x][i]==fa) continue;
    37         dfs2(mp[x][i],x);
    38         dp[x]+=dp[mp[x][i]];
    39         mx=max(mx,dp[mp[x][i]]); 
    40     }
    41     mx=max(mx,num2-dp[x]);
    42     if (mx<mi2){
    43         mi2=mx;
    44         id2=x;
    45     }
    46 }
    47 void dfs3(int x,int fa){
    48     num[x]=1;
    49     for (int i=0;i<mp[x].size();i++){
    50         if (mp[x][i]==fa) continue;
    51         dfs3(mp[x][i],x);
    52         num[x]+=num[mp[x][i]];
    53     }
    54 }
    55 void dfsans(int x,int fa){
    56     for (int i=0;i<mp[x].size();i++){
    57         if (mp[x][i]==fa) continue;
    58         dfsans(mp[x][i],x);
    59         ans+=1ll*(num[mp[x][i]]*(n-num[mp[x][i]]));
    60     }
    61 }
    62 int main(){
    63     int x,y,rt;  scanf("%d",&n);
    64     for (int i=0;i<n-2;i++){
    65         scanf("%d%d",&x,&y);
    66         mp[x].push_back(y);
    67         mp[y].push_back(x);
    68         vis[i]=0; num[i]=0;
    69     }
    70     dfs(1,0);
    71     num1=0; for (int i=1;i<=n;i++) if (vis[i]) num1++;
    72     num2=n-num1;
    73     mi1=2*n,mi2=2*n;
    74     dfs1(1,0);
    75     for (int i=1;i<=n;i++) if (!vis[i]){rt=i; break;}
    76     dfs2(rt,0);
    77     //cout << id1 << "   " << id2<< endl;
    78     dfs3(id1,0);
    79     dfs3(id2,0);
    80     //cout << num[id1] << "   " << num[id2] << endl;
    81     ans=0;
    82     dfsans(id1,0); dfsans(id2,0);
    83     ans+=1ll*(num[id1]*num[id2]);
    84     printf("%lld
    ",ans);
    85     return 0;
    86 }
    A

    B.Math

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=6568

     

    C.Trap

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=6569

    题意:有$n$个长度为$a_i$的线段,问可以构成等腰梯形的方案数为多少。且等腰梯形的四条边的$gcd=1$,全等的两个等腰梯形不重复计算。

    数据范围:$1<=n<=2000,2<=a_i<=10000$。

    分析: 要求四条边的$gcd=1$,那么就先考虑有多少的情况是满足的。

    暴力枚举上下底$xy,$,然后再枚举腰$aa$,满足gcd(x,y,aa)=1 && num[aa]>=2。同时构成等腰梯形还有一个要求是腰的长度不小于上下底差的一半。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=2010;
     4 int a[maxn],id[maxn*10];
     5 int aa[maxn][maxn];
     6 vector<int> g[maxn*10];
     7 set<int> s;
     8 map<int,int> mp;
     9 int gcd_(int x,int y){
    10     if(y==0) return x;
    11     else return gcd_(y,x%y);
    12 }
    13 int solve(int id,int aa,int x,int y){
    14     auto it=lower_bound(g[id].begin(),g[id].end(),aa);
    15     if (it==g[id].end()) return 0;
    16     int res=it-g[id].begin();
    17     res=g[id].size()-res;
    18     if (mp[x]==2){
    19         int tmp=*lower_bound(g[id].begin(),g[id].end(),x);
    20         if (tmp==x && tmp>=aa) res--;
    21     } 
    22     if (mp[y]==2){
    23         int tmp=*lower_bound(g[id].begin(),g[id].end(),y);
    24         if (tmp==y && y>=aa) res--;
    25     }
    26     return res;
    27 }
    28 int main(){
    29     int n;
    30     while (~scanf("%d",&n)){
    31         s.clear();mp.clear();
    32         for (int i=1;i<=n;i++){
    33             scanf("%d",&a[i]);
    34             mp[a[i]]++;
    35         }
    36         sort(a+1,a+1+n);
    37         n=unique(a+1,a+1+n)-(a+1);
    38         for (int i=1;i<=n;i++){
    39             for (int j=i+1;j<=n;j++){
    40                 aa[i][j]=gcd_(a[i],a[j]);
    41                 s.insert(aa[i][j]);
    42             }
    43         }
    44         int tot=0;
    45         for (auto i:s) id[i]=++tot; 
    46         for (int i=1;i<=n;i++){
    47             for (auto j:s){
    48                 int tmp=gcd_(a[i],j);
    49                 if (tmp==1 && mp[a[i]]>=2){
    50                     g[id[j]].push_back(a[i]);
    51                 }
    52             }
    53         }
    54         int ans=0;
    55         for (int i=1;i<=n;i++){//上底 
    56             for (int j=i+1;j<=n;j++){//下底 
    57                 int d=(a[j]-a[i])/2+1;
    58                 int tmp=solve(id[aa[i][j]],d,a[i],a[j]);
    59                 (ans+=tmp); 
    60             }
    61         }
    62         printf("%d
    ",ans);
    63         for (int i=1;i<=tot;i++) g[i].clear();
    64     }
    65     return 0;
    66 } 
    C

    D.Wave

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=6570

    题意:给一个$n$个数的序列,包含$1-c$范围内的数,要求求解一个序列要求如下:

    奇数位数字相同;偶数位数字相同;奇偶位不同。问,这样的序列最长的为多长?

    数据范围:$1<=n<=10^5,1<=c<=100$。

    分析:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1e5+7;
     4 struct node{int num,cnt;} dp[110][110];
     5 int a[maxn];
     6 int main()
     7 {
     8     int n,c;
     9     while (~scanf("%d%d",&n,&c))
    10     {
    11         for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    12         for (int i=1;i<=c;i++)
    13             for (int j=1;j<=c;j++) dp[i][j].cnt=0,dp[i][j].num=i;
    14         for (int i=1;i<=n;i++)
    15         {
    16             int x=a[i];
    17             for (int i=1;i<=c;i++)
    18             {
    19                 if(x==i) continue;
    20                 if(dp[i][x].num==x) {dp[i][x].cnt++;dp[i][x].num=i;}
    21                 if(dp[x][i].num==x) {dp[x][i].cnt++;dp[x][i].num=i;}
    22             }
    23         }
    24         int ans=0;
    25         for (int i=1;i<=c;i++)
    26             for (int j=1;j<=c;j++) ans=max(ans,dp[i][j].cnt);
    27         printf("%d
    ",ans);
    28     }
    29     return 0;
    30 }
    D

    E.Packing

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=6571

     

    F.String

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=6572

    题意:给你一个只包含$a,v,i,n$的长度为$n$的字符串,问依此选取$a,v,i,n$的概率是多少。

    数据范围:$1<=n<=100$。

    分析:乘法原理。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 map<int,int> mp;
     4 int num[5];
     5 int gcd_(int xx,int yy){
     6     if (yy==0) return xx;
     7     else return gcd_(yy,xx%yy);
     8 }
     9 int main(){
    10     int n;char ch; mp['a']=1; mp['v']=2; mp['i']=3; mp['n']=4;
    11     while (~scanf("%d",&n)){
    12         getchar();
    13         memset(num,0,sizeof(num));
    14         for (int i=1;i<=n;i++){
    15             scanf("%c",&ch);
    16             num[mp[ch]]++;
    17         }
    18         int xx=1,yy=n*n*n*n;
    19         for (int i=1;i<=4;i++){
    20             xx*=num[i];
    21         }
    22         if (xx==0){
    23             printf("0/1
    ");
    24             continue;
    25         }
    26         int tmp=gcd_(xx,yy);
    27         xx/=tmp; yy/=tmp;
    28         printf("%d/%d
    ",xx,yy);
    29     }
    30     return 0;
    31 }
    F

    G.Traffic

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=6573

    题意:东西向有$n$辆车,南北向有$m$辆车,他们通过路口时时间分别为$a_i,b_i$。问南北向的车最少等待多久可以保证没有车相撞。

    数据范围:$1<=n,m<=1000,1<=a_i, b_i<=1000$。

    分析:枚举等待时间,满足条件即break。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1010;
     4 int a[maxn],b[maxn],c[maxn*2];
     5 int n,m;
     6 int main() {
     7     while (~scanf("%d%d",&n,&m)){
     8         for (int i=1;i<=n;i++) scanf("%d",&a[i]);
     9         for (int i=1;i<=m;i++) scanf("%d",&b[i]);
    10         sort(a+1,a+1+n);
    11         sort(b+1,b+1+m);
    12         int kk=0;
    13         while (1){
    14             int num=0;
    15             for (int i=1;i<=n;i++) c[++num]=a[i];
    16             for (int i=1;i<=m;i++) c[++num]=b[i]+kk;
    17             sort(c+1,c+1+num);
    18             int m=unique(c+1,c+1+num)-(c+1);
    19             if (m==num) break;
    20             else kk++;
    21         }
    22         printf("%d
    ",kk);
    23     }
    24     return 0;
    25 }
    G

    H.Rng

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=6574

    题意:在$1-n$范围内先选取区间的右界$r$,再在$1-r$内选取左界$l$。问任取两个区间相交的概率为多少。

    数据范围:$1<=n<=10^6$。

    分析:容斥原理。分析不相交的概率为多少。

    和学妹们手推QAQ.

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int mod=1e9+7;
     5 ll pow_(ll x,int y){
     6     ll res=1,base=1ll*x;
     7     while (y){
     8         if (y&1) (res*=base)%=mod;
     9         (base*=base)%=mod;
    10         y>>=1;
    11     }
    12     return res;
    13 }
    14 int main(){
    15     int n;
    16     while (~scanf("%d",&n)){
    17         ll ans=(1ll*(n+1)*pow_(2ll*n,mod-2))%mod;
    18         printf("%lld
    ",ans);
    19     }
    20     return 0;
    21 } 
    H

    I.Budget

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=6575

    题意:有$n$个三位小数,要求四舍五入到两位小数,每次取四舍五入后的数与原数的差值,问全部差值的和为多少。

    数据范围:$1<=n<=1000$。

    分析:签到。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1e5+7;
     4 int main()
     5 {
     6     int n;
     7     while (~scanf("%d",&n))
     8     {
     9         string s;
    10         double ans=0;
    11         while (n--)
    12         {
    13             cin>>s;
    14             int st=s.length(),f;
    15             for (int i=0;i<st;i++) 
    16                 if(s[i]=='.'){f=i;break;}
    17             int x=s[f+3]-'0';
    18             if(x>=5) ans+=10-x;
    19             else ans-=x;
    20         }
    21         ans/=1000.0;
    22         printf("%.3f
    ",ans);
    23     }
    24     return 0;
    25 }
    I

    J.Worker

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=6576

    题意:有$n$个工作间,$m$个工人,每个工作间每天每人能完成的工作量为$a_i$,问能否将这$m$个人分配到这$n$个工作间,要求每个工作间每天能完成的工作量相同。可以分配输出每个工作间分配的人数。

    数据范围:$1<=n<=1000,1<=m<=10^{18}$。

    分析:考虑所有$a_i$的最小公倍数,然后得到每个工作间人数比例,再判断是否可分。签到++。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn=1010;
     5 ll a[maxn],b[maxn];
     6 ll gcd_(ll xx,ll yy){
     7     if (yy==0) return xx;
     8     else return gcd_(yy,xx%yy);
     9 }
    10 int main(){
    11     ll n,m;
    12     while (~scanf("%lld%lld",&n,&m)){
    13         for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    14         ll tmp=a[1];
    15         for (int i=2;i<=n;i++){
    16             ll kk=gcd_(a[i],tmp);
    17             tmp=tmp/kk*a[i];
    18         }
    19         ll sum=0;
    20         for (int i=1;i<=n;i++){
    21             b[i]=tmp/a[i];
    22             sum+=b[i];
    23         }
    24         if (m%sum!=0){
    25             printf("No
    ");
    26             continue;
    27         }
    28         printf("Yes
    "); 
    29         ll t=m/sum;
    30         printf("%lld",t*b[1]);
    31         for (int i=2;i<=n;i++){
    32             printf(" %lld",t*b[i]);
    33         }
    34         printf("
    ");
    35     }
    36     return 0;
    37 }
    J

    K.Class

    传送:http://acm.hdu.edu.cn/showproblem.php?pid=6577

    题意:已知$x=a+b,y=a-b$。求解$a*b$。

    分析:$a=frac{x+y}{2},b=frac{x-y}{2}$。签到++。

    1 #include<bits/stdc++.h>
    2 using namespace std;
    3 int main(){
    4     int x,y;scanf("%d%d",&x,&y);
    5     int tmp=(x*x-y*y)/4;
    6     printf("%d
    ",tmp);
    7     return 0;
    8 } 
    K

     

  • 相关阅读:
    python 面向对象之路(1) 类和对象 三大特性 封装 继承 多态
    python 模块之路 异常处理基础 异常处理其他 报错处理
    python 模块之路 序列化 json pickle
    python 模块之路 random模块 时间模块 sys模块 os模块
    python 模块之路 re模块运用
    python -模块之路 正则表达式
    【Unity】粒子特效优化实践
    快速实现Low Poly地形
    【Unity】屏幕空间位置变换到世界空间位置的方法
    Substance Designer 使用手册
  • 原文地址:https://www.cnblogs.com/changer-qyz/p/11223404.html
Copyright © 2011-2022 走看看