• 2016 Multi-University Training Contest 1


    官方题解:http://bestcoder.hdu.edu.cn/blog/2016-multi-university-training-contest-1-solutions-by-hit/

    题目链接:

     A  http://acm.hdu.edu.cn/showproblem.php?pid=5723

    第一步求最小生成树,因为题目限制边权各不相同,所以最小生成树唯一。第二步求任意树上任意两点距离的均值,通过计算每条边对总和的贡献得到。枚举每条边,经过次数等于该边左边点的个数乘右边点的个数。dfs求有根树每个点子树节点个数的办法。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int M=1e6+10;
      4 struct E {
      5     int u,v;
      6     double w;
      7 } e[M];
      8 int n,m;
      9 double cost;
     10 double average;
     11 struct G{
     12     struct E{
     13         int v,next;
     14         double w;
     15     }e[M];
     16     int le,head[M];
     17     void init(int n){
     18         le=0;
     19         for(int i=0;i<=n;i++) head[i]=-1;
     20     }
     21     void add(int u,int v,double w){
     22         e[le].v=v;
     23         e[le].w=w;
     24         e[le].next=head[u];
     25         head[u]=le++;
     26     }
     27 }g;
     28 class Kruskal { ///最小生成树(无向图) O(E*log(E))
     29     typedef double typec; ///边权的类型
     30     static const int ME=1e6+10; ///边的个数
     31     static const int MV=1e5+10; ///点的个数
     32     class UnionFindSet { ///并查集
     33         int par[MV];
     34         void add(int son,int fa) {
     35             par[fa]+=par[son];
     36             par[son]=fa;
     37         }
     38     public:
     39         void init(int n) {
     40             for(int i=0; i<=n; i++) par[i]=-1;
     41         }
     42         int getroot(int x) {
     43             int i=x,j=x,temp;
     44             while(par[i]>=0) i=par[i];
     45             while(j!=i) {
     46                 temp=par[j];
     47                 par[j]=i;
     48                 j=temp;
     49             }
     50             return i;
     51         }
     52         bool unite(int x,int y) {
     53             int p=getroot(x);
     54             int q=getroot(y);
     55             if(p==q) return false;
     56             if(par[p]>par[q]) {
     57                 add(p,q);
     58             }
     59             else {
     60                 add(q,p);
     61             }
     62             return true;
     63         }
     64     } ufs;
     65     struct E {
     66         int u,v;
     67         typec w;
     68         friend bool operator < (const E &a,const E &b) {
     69             return a.w<b.w;
     70         }
     71     } e[ME];
     72     int le,num,n;
     73     typec res;
     74 public:
     75     void init(int tn) { ///传入点的个数
     76         n=tn;
     77         le=0;
     78     }
     79     void add(int u,int v,typec w) {
     80         e[le].u=u;
     81         e[le].v=v;
     82         e[le].w=w;
     83         le++;
     84     }
     85     typec solve() { ///返回-1 不连通
     86         res=0;
     87         num=1;
     88         ufs.init(n);
     89         sort(e,e+le);
     90         for(int i=0; i<le&&num<n; i++) {
     91             if(ufs.unite(e[i].u,e[i].v)) {
     92                 num++;
     93                 res+=e[i].w;
     94                 g.add(e[i].u,e[i].v,e[i].w);
     95                 g.add(e[i].v,e[i].u,e[i].w);
     96             }
     97         }
     98         if(num<n) res=-1;
     99         return res;
    100     }
    101 } mst;
    102 int dfs(int u,int fa){
    103     int sum=1;
    104     for(int i=g.head[u];~i;i=g.e[i].next){
    105         int v=g.e[i].v;
    106         if(v==fa) continue;
    107         double w=g.e[i].w;
    108         int son=dfs(v,u);
    109         sum+=son;
    110         average+=w*son*(n-son);
    111     }
    112     return sum;
    113 }
    114 void solve() {
    115     g.init(n);
    116     mst.init(n);
    117     for(int i=0;i<m;i++){
    118         mst.add(e[i].u,e[i].v,e[i].w);
    119     }
    120     cost=mst.solve();
    121     average=0;
    122     dfs(1,-1);
    123     average*=2;
    124     average/=n;
    125     average/=(n-1);
    126 }
    127 int main() {
    128     int t;
    129     while(~scanf("%d",&t)) {
    130         while(t--) {
    131             scanf("%d%d",&n,&m);
    132             for(int i=0; i<m; i++) {
    133                 scanf("%d%d%lf",&e[i].u,&e[i].v,&e[i].w);
    134             }
    135             solve();
    136             printf("%.0f %.2f
    ",cost,average);
    137         }
    138     }
    139     return 0;
    140 }
    View Code

    http://acm.hdu.edu.cn/showproblem.php?pid=5724

    博弈,nim,

    标程是递推的,会比我快一点,我写的是记忆化搜素,更符合正向思维。sg函数=所有后继状态sg值中,最小的不出现的非负整数。定理。多个游戏组合的和,等于多个游戏sg值的异或。

     1 #include<bits/stdc++.h>
     2 #define mt(a,b) memset(a,b,sizeof(a))
     3 using namespace std;
     4 const int M=1e3+10;
     5 int n,m[M];
     6 int a[M][M];
     7 char answer[2][8]={"NO","YES"};
     8 int sg[1<<20];
     9 void init(){
    10     mt(sg,-1);
    11 }
    12 int dfs(int sta){
    13     int &g=sg[sta];
    14     if(~g) return g;
    15     bool s[20];
    16     mt(s,0);
    17     int zero=-1;
    18     for(int i=0;i<20;i++){
    19         if(!((sta>>i)&1)){
    20             zero=i;
    21             continue;
    22         }
    23         if(zero==-1) continue;
    24         s[dfs(sta^(1<<i)^(1<<zero))]=true;
    25     }
    26     for(int i=0;i<32;i++){
    27         if(s[i]) continue;
    28         g=i;
    29         break;
    30     }
    31     return g;
    32 }
    33 int solve(){
    34     int nim=0;
    35     for(int i=0;i<n;i++){
    36         int sta=0;
    37         for(int j=0;j<m[i];j++){
    38             sta|=(1<<(20-a[i][j]));
    39         }
    40         nim^=dfs(sta);
    41     }
    42     return nim!=0;
    43 }
    44 int main(){
    45     init();
    46     int t;
    47     while(~scanf("%d",&t)){
    48         while(t--){
    49             scanf("%d",&n);
    50             for(int i=0;i<n;i++){
    51                 scanf("%d",&m[i]);
    52                 for(int j=0;j<m[i];j++){
    53                     scanf("%d",&a[i][j]);
    54                 }
    55             }
    56             puts(answer[solve()]);
    57         }
    58     }
    59     return 0;
    60 }
    View Code

    递推预处理写法

     1 #include<bits/stdc++.h>
     2 #define mt(a,b) memset(a,b,sizeof(a))
     3 using namespace std;
     4 const int M=1e3+10;
     5 const int total=1<<20;
     6 int n,m[M];
     7 int a[M][M];
     8 char answer[2][8]={"NO","YES"};
     9 int sg[total];
    10 bool had[20];
    11 void init(){
    12     for(int i=0;i<total;i++){
    13         mt(had,0);
    14         int zero=-1;
    15         for(int j=0;j<20;j++){
    16             if(!((i>>j)&1)){
    17                 zero=j;
    18                 continue;
    19             }
    20             if(zero==-1) continue;
    21             had[sg[i^(1<<j)^(1<<zero)]]=true;
    22         }
    23         for(int j=0;;j++){
    24             if(had[j]) continue;
    25             sg[i]=j;
    26             break;
    27         }
    28     }
    29 }
    30 int solve(){
    31     int nim=0;
    32     for(int i=0;i<n;i++){
    33         int sta=0;
    34         for(int j=0;j<m[i];j++){
    35             sta|=(1<<(20-a[i][j]));
    36         }
    37         nim^=sg[sta];
    38     }
    39     return nim!=0;
    40 }
    41 int main(){
    42     init();
    43     int t;
    44     while(~scanf("%d",&t)){
    45         while(t--){
    46             scanf("%d",&n);
    47             for(int i=0;i<n;i++){
    48                 scanf("%d",&m[i]);
    49                 for(int j=0;j<m[i];j++){
    50                     scanf("%d",&a[i][j]);
    51                 }
    52             }
    53             puts(answer[solve()]);
    54         }
    55     }
    56     return 0;
    57 }
    View Code

     D http://acm.hdu.edu.cn/showproblem.php?pid=5726

    第一问求一个区间的gcd,第二问求等于这个值的有多少个区间。比赛时的做法,第一问通过rmq预处理,复杂度n*logn*gcd,查询gcd。  第二问枚举起点,对每个起点,gcd分段递减,对每一段二分出段的尾部,然后这段的gcd值都相同,用map记录,每个起点最多logai段。复杂度n*logn*loga*gcd。查询log。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 const int M=1e5+10;
     5 int n,m;
     6 int a[M];
     7 struct Q {
     8     int x,y,gcd;
     9     LL sum;
    10 } q[M];
    11 int gcd(int a,int b){
    12     return b?gcd(b,a%b):a;
    13 }
    14 class RMQ { ///区间最值查询(ST)离线算法 init O(n*logn) query O(1)
    15     typedef int typec; ///点权类型
    16     static const int M=1e5+10; ///点的个数
    17     int LOG[M];
    18     typec dpmax[M][20];
    19 public:
    20     RMQ() {
    21         LOG[0]=-1;
    22         for(int i=1; i<M; i++) {
    23             LOG[i]=LOG[i>>1]+1;
    24         }
    25     }
    26     void init(int n,typec a[]) { ///传入点的个数,下标 1 开始
    27         for(int i=1; i<=n; i++) {
    28             dpmax[i][0]=a[i];
    29         }
    30         for(int j=1; j<=LOG[n]; j++) {
    31             for(int i=1; i+(1<<j)-1<=n; i++) {
    32                 int k=i+(1<<(j-1));
    33                 dpmax[i][j]=gcd(dpmax[i][j-1],dpmax[k][j-1]);
    34             }
    35         }
    36     }
    37     typec get(int a,int b) { ///传入 1 返回 max,传入 0 返回 min
    38         int k=LOG[b-a+1];
    39         b=b-(1<<k)+1;
    40         return gcd(dpmax[a][k],dpmax[b][k]);
    41     }
    42 } rmq;
    43 map<int,LL> mp;
    44 int binary(int s,int head,int g){
    45     int L=head,R=n,result=L;
    46     while(L<=R){
    47         int mid=(L+R)>>1;
    48         if(rmq.get(s,mid)==g){
    49             result=mid;
    50             L=mid+1;
    51         }
    52         else{
    53             R=mid-1;
    54         }
    55     }
    56     return result;
    57 }
    58 void init() {
    59     mp.clear();
    60     for(int i=1;i<=n;i++){
    61         int head=i;
    62         while(head<=n){
    63             int g=rmq.get(i,head);
    64             int tail=binary(i,head,g);
    65             mp[g]+=tail-head+1;
    66             head=tail+1;
    67         }
    68     }
    69 }
    70 void solve() {
    71     rmq.init(n,a);
    72     init();
    73     for(int i=0;i<m;i++){
    74         q[i].gcd=rmq.get(q[i].x,q[i].y);
    75         q[i].sum=mp[q[i].gcd];
    76     }
    77 }
    78 int main() {
    79     int t;
    80     while(~scanf("%d",&t)) {
    81         int cas=1;
    82         while(t--) {
    83             scanf("%d",&n);
    84             for(int i=1; i<=n; i++) {
    85                 scanf("%d",&a[i]);
    86             }
    87             scanf("%d",&m);
    88             for(int i=0; i<m; i++) {
    89                 scanf("%d%d",&q[i].x,&q[i].y);
    90             }
    91             solve();
    92             printf("Case #%d:
    ",cas++);
    93             for(int i=0; i<m; i++) {
    94                 printf("%d %I64d
    ",q[i].gcd,q[i].sum);
    95             }
    96         }
    97     }
    98     return 0;
    99 }
    View Code

    D 标程的解法会少一个logn,因为找不同的gcd段时不二分,而是把每一个点作为终点的情况存下,存某个终点各个段的gcd值和起点。当处理 x 为终点的时, x-1的段的结果可以利用上,类似单调队列。也就是说,增加了a【x】,前面的段断点都可能是新的断点,实现起来不太好理解。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 const int M=1e5+10;
     5 int n,m;
     6 int a[M];
     7 struct Q {
     8     int x,y,gcd;
     9     LL sum;
    10 } q[M];
    11 int gcd(int a,int b){
    12     return b?gcd(b,a%b):a;
    13 }
    14 map<int,LL> mp;
    15 typedef pair<int,int> pii;
    16 vector<pii> block[M];
    17 void solve() {
    18     mp.clear();
    19     for(int i=0;i<=n;i++){
    20         block[i].clear();
    21     }
    22     for(int i=1;i<=n;i++){
    23         int last=0;
    24         for(int j=0;j<block[i-1].size();j++){
    25             int head=block[i-1][j].first;
    26             int g=block[i-1][j].second;
    27             int nowgcd=gcd(g,a[i]);
    28             if(nowgcd==last) continue;
    29             last=nowgcd;
    30             block[i].push_back(make_pair(head,nowgcd));
    31         }
    32         if(a[i]!=last){
    33             block[i].push_back(make_pair(i,a[i]));
    34         }
    35         for(int j=0;j<block[i].size();j++){
    36             int head=block[i][j].first;
    37             int g=block[i][j].second;
    38             int tail=i;
    39             if(j+1<block[i].size()){
    40                 tail=block[i][j+1].first-1;
    41             }
    42             mp[g]+=tail-head+1;
    43         }
    44     }
    45     for(int i=0;i<m;i++){
    46         int L=0,R=block[q[i].y].size()-1,result=L;
    47         while(L<=R){
    48             int mid=(L+R)>>1;
    49             if(block[q[i].y][mid].first<=q[i].x){
    50                 result=mid;
    51                 L=mid+1;
    52             }
    53             else{
    54                 R=mid-1;
    55             }
    56         }
    57         q[i].gcd=block[q[i].y][result].second;
    58         q[i].sum=mp[q[i].gcd];
    59     }
    60 }
    61 int main() {
    62     int t;
    63     while(~scanf("%d",&t)) {
    64         int cas=1;
    65         while(t--) {
    66             scanf("%d",&n);
    67             for(int i=1; i<=n; i++) {
    68                 scanf("%d",&a[i]);
    69             }
    70             scanf("%d",&m);
    71             for(int i=0; i<m; i++) {
    72                 scanf("%d%d",&q[i].x,&q[i].y);
    73             }
    74             solve();
    75             printf("Case #%d:
    ",cas++);
    76             for(int i=0; i<m; i++) {
    77                 printf("%d %I64d
    ",q[i].gcd,q[i].sum);
    78             }
    79         }
    80     }
    81     return 0;
    82 }
    View Code

    end

  • 相关阅读:
    SpringCloud系列——TX-LCN分布式事务管理
    SpringCloud系列——限流、熔断、降级
    SpringBoot系列——Logback日志,输出到文件以及实时输出到web页面
    常用的js、java编码解码方法
    WebSocket数据加密——AES与RSA混合加密
    使用Fiddler重定向App的网络请求
    C# 调用 taskkill命令结束服务进程
    Install .Net Core For CentOS
    cron表达式详解[转]
    WinServer远程部署系统打包批处理文件
  • 原文地址:https://www.cnblogs.com/gaolzzxin/p/5688015.html
Copyright © 2020-2023  润新知