Codeforces Round #362 (Div. 2)(A~D))

来源:互联网 发布:腾讯文件管理器源码 编辑:程序博客网 时间:2024/06/10 09:56

目前水平有限,补了四题。。。
感觉这场质量很高,没有白补。
A. Pineapple Incident
题意&思路:水题

#include<bits/stdc++.h>using namespace std;int main(){    int t,s,x;    while(cin>>t>>s>>x){      if(x==t||(x-t)%s==0&&x>t||(x-t-1)%s==0&&(x-t-1>0)) printf("YES\n");      else printf("NO\n");    }}

B. Barnicle
题意&思路:字符串模拟一下科学计数法转换,注意下细节。
这几个数据容易错:
8.77056e6
7.0e100
1.0e0
0.0e10

#include<bits/stdc++.h>using namespace std;int main(){   string s;   while(cin>>s){      int nz=0,a,e,b=0,ok=0;      a=s[0]-'0';      for(int i=2;i<s.size();i++){          if(s[i]=='e') { e=i;ok=1;}          else if(!ok&&s[i]>='1'&&s[i]<='9') nz=i;          else if(ok) b=b*10+s[i]-'0';      }      ok=0;      if(a||b==0) { cout<<a;ok=1;}      if(b>=nz-1){         for(int i=2;i<=nz;i++){            if(ok||s[i]!='0') cout<<s[i],ok=1;         }         if(nz==0) nz=1;         for(int i=0;i<b-nz+1;i++) cout<<0;         cout<<endl;      }      else{         for(int i=2;i<b+2;i++){            if(ok||s[i]!='0') cout<<s[i],ok=1;         }         cout<<".";         for(int i=b+2;i<=nz;i++) cout<<s[i];         cout<<endl;      }   }}

C. Lorenzo Von Matterhorn
题意:在一棵根为1的二叉搜索树上(每个点的子孙是他的两倍和两倍+1),在这个树上更新任意两点之间的边的权值,和询问树上任意两点之间边之和。
思路:在一棵二叉搜索树上,边之间点都是2^n增加,所以直接暴力复杂度O(logn),范围10^18,
就用map。

#include<bits/stdc++.h>using namespace std;typedef long long ll;map<ll,ll>m;int main(){     int q;cin>>q;     m.clear();     while(q--){        ll o,u,v;cin>>o>>u>>v;        if(o==1){            ll w;cin>>w;            while(u!=v){                if(u>v) swap(u,v);                m[v]+=w;                v/=2;            }        }        else{            ll ans=0;            while(u!=v){                if(u>v) swap(u,v);                ans+=m[v];                v/=2;            }            cout<<ans<<endl;        }     }}

D.Puzzles
题意:给你一棵树,然后让你从1点dfs,但是dfs的时候如果有多个结点,那么则随机选一个结点去访问,最后问你每个点访问时间的期望,假设访问一个结点用时1s。
思路:
案例
分析一颗子树:

当前已知节点1的期望为1.0 ->anw[1]=1.0
需要通过节点1递推出节点2、4、5的期望值

1的儿子分别是2、4、5,那么dfs序所有可能的排列是6种:
1:1-2-4-5 (2、4、5节点的儿子没有写出)
2:1-2-5-4
3:1-4-2-5
4:1-4-5-2
5:1-5-2-4
6:1-5-4-2
这六种情况分别:
都有一部分:2都是从1转移过来,首先共有ans[1]+1;
第二部分:当节点1到达节点2的时候贡献是0,种类分别对应(1、2)
当先到达节点4后到节点2的时候贡献(size(4)+size(4)+szie(5)),种类分别对应(3、4)
当先到达节点5后到节点2的时候贡献(size(5)+size(5)+size(4)),种类分别对应(5、6)
而所有的排列对于的概率都是1/6,所以第二部分的贡献就是(0+size(4)*3+size(5)*3)/6 = (size(4)+size(5))/2=(size(1)-size(6)-1)/2
多找几棵子树就可以发现 对于第二部分求法有推导: ans[v]=(size(u)-size(v)-1)/2
可以这样理解:对于v点,当走到他的父亲u点时,它可以选择最优一步到v,即贡献为0,也可以最差,走完u点其他所有点后最后到v,即贡献度为size[u]-size[v]-1;

#include<bits/stdc++.h>using namespace std;template<int N,int M>//N点的个数,M边的个数struct Graph{    int top;    struct Vertex{        int head;    }V[N];    struct Edge{        int v,next;    }E[M];    void init(){        memset(V,-1,sizeof(V));        top = 0;    }    void add_edge(int u,int v){        E[top].v = v;        E[top].next = V[u].head;        V[u].head = top++;    }};Graph<100000+10,100000*2+10> g;int sum[100000+10];double ans[100000+10];void dfs1(int u,int f){   sum[u]=1;   for(int i=g.V[u].head;i!=-1;i=g.E[i].next){      int v=g.E[i].v;      if(v==f) continue;      dfs1(v,u);      sum[u]+=sum[v];   }}void dfs2(int u,int f){   for(int i=g.V[u].head;i!=-1;i=g.E[i].next){      int v=g.E[i].v;      if(v==f) continue;      ans[v]=ans[u]+1.0+(sum[u]-sum[v]-1)*0.5;      dfs2(v,u);   }}int main(){    int n;    while(~scanf("%d",&n)){        g.init();        memset(sum,0,sizeof(sum));        for(int i=2;i<=n;i++){            int x;scanf("%d",&x);            g.add_edge(x,i);            g.add_edge(i,x);        }        memset(ans,0,sizeof(ans));        dfs1(1,-1);        ans[1]=1.0;        dfs2(1,-1);        for(int i=1;i<n;i++) printf("%.2f ",ans[i]);        printf("%.2f\n",ans[n]);    }}
0 0
原创粉丝点击