• HNOI2015 Day 1


    HNOI2015的题还是非常漂亮的,几道题都有很大的借鉴意义,都有很强的思考性

    T1亚瑟王(概率论)

    描述:http://www.lydsy.com/JudgeOnline/problem.php?id=4008

    我们可以发现这个模型可以转化成有r个机会给n个人,每个人对每个机会都有一定的概率拿,求收益的期望

    那么记f[i][j]为第i个人有j个机会的概率,那么可以得出

    f[i+1][j]+=f[i][j]*(1-p[i])^j

    f[i+1][j-1]+=f[i][j]*(1-(1-p[i])^j)

    就可以完美解决这个问题了

    这道题的重点是把这个模型进行转化(可以直观了理解吧n和r对换过来),否则按 f[i][j]为第i轮到第j个的概率的话搞到死都做不出(我就是这样QAQ),在做概率题的时候模型转换是第一步也是最重要的一步

    Code:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<cstring>
     5 using namespace std;
     6 #define maxn 222
     7 double f[maxn][maxn],p[maxn];
     8 int d[maxn];
     9 int main(){
    10     int t;
    11     scanf("%d",&t);
    12     while (t--) {
    13         memset(f,0,sizeof(f));
    14         int n,r;
    15         scanf("%d%d",&n,&r);
    16         for (int i=1;i<=n;i++) scanf("%lf%d",p+i,d+i);
    17         memset(f,0,sizeof(f));
    18         f[1][r]=1;
    19         double ans=0;
    20         for (int i=1;i<=n;i++) {
    21             double tmp=1;
    22             for (int j=1;j<=r;j++){
    23                 tmp*=1-p[i];
    24                 f[i+1][j]+=f[i][j]*tmp;
    25                 f[i+1][j-1]+=f[i][j]*(1-tmp);
    26                 ans+=f[i][j]*(1-tmp)*d[i];
    27             }
    28         }
    29         printf("%.10lf
    ",ans);
    30     }
    31     return 0;
    32 }
    View Code

    T2:接水果(数据结构)

    描述:http://www.lydsy.com/JudgeOnline/problem.php?id=4009

    ORZ clj出的神题

    由于省特派员送温暖,各种写法都水过了QAQ

    连暴力在八中都能过这是什么回事QAQ

    先讲下水法把= =

    解法一:(暴力)

    直接读入每个盘子后排下序,用lca判断覆盖就离线tarjan搞,复杂度O(n^2),水过了!!!

    解法二:(树链剖分+主席树+可持久化treap)

    先把那棵树树链剖分掉,然后考虑在没有主席树的远古时代人们用的方法——平衡树,那么我们对每一个树节点建立一棵主席树,每个主席树树节点维护一个可持久化Treap,存起点在该点在该树节点的重链上,终点在主席树的该区间中所有盘子的w值,那么我们每次就可以二分答案,把log n棵主席树,每棵主席树中的log n个区间中小于该答案的盘子数算出来= =总的时间复杂度O(n log^4 n)~~~

    解法三:(点剖+树链剖分+主席树套权值线段树)

    由于某同学的口胡,我至今仍搞不清为何要先点剖= =,大致思想跟解法二差不多,但是就吧treap换成权值线段树,总时间复杂度貌似为(O(n log^3 n)(某同学说的))

    解法四:(树上莫队+平衡树)

    既然题目允许离线那就考虑用树上莫队解决,对当前的两个询问点u,v维护他们的相对差(也就是u到根的信息-v到根的信息),lca上的信息需要特判一下,如果我的盘子的起点和终点都在我的相对差中就加入平衡树,然后在log n查询即可,分块上每根号n个一块即可通过本题,总的时间复杂度O(nsqrt(n)log n)

    解法五:(正解,扫描线+树状数组套权值线段树)

    还是离线,把每个点重标号为其dfs序,每个询问抽象成二维平面坐标中的点(u,v)。可发现每个盘子所控制的坐标为若干个矩形区域。

    具体来说,如果两个盘子的坐标与其lca不同,那么就是起点与终点在u,v的子树中是符合要求的

    否则,就是一个在子树中,另一个不在lca的那个子树中

    那么问题就变成了一个经典问题:询问在某点上的矩形的第k大

    扫描线+树状数组套权值线段树秒过

    时间复杂度O(n log^2 n)

    Code:

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<vector>
      6 using namespace std;
      7 #define maxn 41000
      8 #define maxk 24
      9 vector<int> e[maxn];
     10 int st[maxn],ed[maxn],dfn[maxn],dep[maxn];
     11 int f[maxn][maxk],clo;
     12 void dfs(int u,int fa) {
     13     st[u]=ed[u]=dfn[u]=++clo;
     14     f[u][0]=fa;dep[u]=dep[fa]+1;
     15     for (int i=1;i<maxk;i++) {
     16         if (f[f[u][i-1]][i-1]==0) break;
     17         f[u][i]=f[f[u][i-1]][i-1];
     18     }
     19     for (int i=0;i<e[u].size();i++) {
     20         if (e[u][i]==fa) continue;
     21         dfs(e[u][i],u);
     22         ed[u]=ed[e[u][i]];
     23     }
     24 }
     25 inline int up(int x,int y) {
     26     for (int i=0;i<maxk;i++) if (y&(1<<i)) x=f[x][i];
     27     return x;
     28 }
     29 inline int lca(int x,int y) {
     30     if (dep[x]<dep[y]) swap(x,y);
     31     x=up(x,dep[x]-dep[y]);
     32     if (x==y) return x;
     33     for (int i=maxk-1;i+1;i--) {
     34         if (f[x][i]==f[y][i]) continue;
     35         x=f[x][i];y=f[y][i];
     36     }
     37     return f[x][0];
     38 }
     39 struct qnode{int x,y1,y2,z,flag;}s[maxn*10];
     40 int l;
     41 inline void add(int x,int y1,int y2,int w,int flag) {
     42     s[++l]=(qnode){x,y1,y2,w,flag};
     43 }
     44 typedef pair<int,int> ii;
     45 #define fi first
     46 #define se second
     47 ii b[maxn];
     48 bool cmp(int x,int y) {return dfn[b[x].fi]<dfn[b[y].fi];}
     49 bool cmp1(qnode x,qnode y){return x.x<y.x;}
     50 struct node{
     51     int lc,rc,s;
     52 }t[maxn*1000];
     53 int cnt;
     54 #define lc(x) t[x].lc
     55 #define rc(x) t[x].rc
     56 #define mid (l+r>>1)
     57 void insert(int &x,int l,int r,int y,int z){
     58     if (x==0) x=++cnt;
     59     t[x].s+=z;
     60     if (l==r) return ;
     61     if (mid>=y) insert(lc(x),l,mid,y,z);
     62     else insert(rc(x),mid+1,r,y,z);
     63 }
     64 int n;
     65 #define lowbit(x) ((x)&(-x))
     66 int r[maxn];
     67 #define inf 0x7fffffff
     68 inline void ins(int x,int y,int z) {
     69     for (;x<=n+3;x+=lowbit(x)) insert(r[x],0,inf,y,z);
     70 }
     71 vector<int> list[33];
     72 #define pb push_back
     73 int solve(int l,int r,int deep,int &k) {
     74     int sum=0;
     75     for (int i=0;i<list[deep].size();i++) sum+=t[list[deep][i]].s;
     76     if (sum<k) {k-=sum;return -1;}
     77     if (sum>=k&&l==r) return l;
     78     list[deep+1].clear();
     79     for (int i=0;i<list[deep].size();i++) if (t[list[deep][i]].lc) list[deep+1].pb(t[list[deep][i]].lc);
     80     int tmp=solve(l,mid,deep+1,k);
     81     if (tmp!=-1) return tmp;
     82     list[deep+1].clear();
     83     for (int i=0;i<list[deep].size();i++) if (t[list[deep][i]].rc) list[deep+1].pb(t[list[deep][i]].rc);
     84     return solve(mid+1,r,deep+1,k);
     85 }    
     86 inline int que(int x,int y,int k) {
     87     list[1].clear();
     88     for (;y;y-=lowbit(y)) if (r[y]) list[1].pb(r[y]);
     89     return solve(0,inf,1,k);
     90 }
     91 int main(){
     92     int p,q;
     93     scanf("%d%d%d",&n,&p,&q);
     94     for (int i=1;i<n;i++) {
     95         int x,y;
     96         scanf("%d%d",&x,&y);
     97         e[x].pb(y);e[y].pb(x);
     98     }
     99     dfs(1,0);
    100     static ii a[maxn];
    101     static int w[maxn],k[maxn];
    102     for (int i=1;i<=p;i++) scanf("%d%d%d
    ",&a[i].fi,&a[i].se,w+i);
    103     for (int i=1;i<=q;i++) scanf("%d%d%d
    ",&b[i].fi,&b[i].se,k+i);
    104     for (int i=1;i<=p;i++) {
    105         int v=lca(a[i].fi,a[i].se);
    106         if (v!=a[i].fi&&v!=a[i].se) {
    107             add(st[a[i].fi],st[a[i].se],ed[a[i].se],w[i],1);
    108             add(ed[a[i].fi]+1,st[a[i].se],ed[a[i].se],w[i],-1);
    109             add(st[a[i].se],st[a[i].fi],ed[a[i].fi],w[i],1);
    110             add(ed[a[i].se]+1,st[a[i].fi],ed[a[i].fi],w[i],-1);
    111         }else {
    112             if (v!=a[i].fi) swap(a[i].fi,a[i].se);
    113             v=up(a[i].se,dep[a[i].se]-dep[a[i].fi]-1);
    114             add(1,st[a[i].se],ed[a[i].se],w[i],1);
    115             add(st[v],st[a[i].se],ed[a[i].se],w[i],-1);
    116             add(ed[v]+1,st[a[i].se],ed[a[i].se],w[i],1);
    117             add(n+1,st[a[i].se],ed[a[i].se],w[i],-1);
    118             add(st[a[i].se],1,st[v]-1,w[i],1);
    119             add(ed[a[i].se]+1,1,st[v]-1,w[i],-1);
    120             add(st[a[i].se],ed[v]+1,n,w[i],1);
    121             add(ed[a[i].se]+1,ed[v]+1,n,w[i],-1);
    122         }
    123     }
    124     static int id[maxn];
    125     for (int i=1;i<=q;i++) id[i]=i;
    126     sort(id+1,id+1+q,cmp);
    127     sort(s+1,s+1+l,cmp1);
    128     int r=1;
    129     static int ans[maxn];
    130     for (int i=1;i<=l;i++) {
    131         while (r<=q&&dfn[b[id[r]].fi]<s[i].x) ans[id[r]]=que(b[id[r]].fi,dfn[b[id[r]].se],k[id[r]]),r++;
    132         ins(s[i].y1,s[i].z,s[i].flag);
    133         ins(s[i].y2+1,s[i].z,-s[i].flag);
    134     }
    135     for (int i=1;i<=q;i++) printf("%d
    ",ans[i]);
    136     return 0;
    137 }
    View Code

    T3:菜肴制作(拓扑序,贪心,构造)

    描述:http://www.lydsy.com/JudgeOnline/problem.php?id=4010

    首先判环这个就不用说了吧

    然后我们必须优先让最小的尽量前,那么我们就必须且只能把最小的点反向边所能遍历到的点删掉

    考虑删最小的点的前一个点,一定是去掉最小点反向边入度为0的最大点删去

    可以继续贪心构造

    那么我们每次就反向遍历求出联通块再做次拓扑序即可

    优先队列 O(n log n)解决

    Code:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<vector>
     7 using namespace std;
     8 #define maxn 100010
     9 struct edges{
    10     int to,next;
    11 }edge[maxn];
    12 int next[maxn],l,in[maxn];
    13 inline void addedge(int x,int y) {
    14     edge[++l]=(edges){y,next[x]},next[x]=l;in[y]++;
    15 }
    16 bool b[maxn];
    17 vector<int> a;
    18 #define pb push_back 
    19 inline void tuopu(int x) {
    20     static priority_queue<int> q;
    21     while (!q.empty()) q.pop();
    22     q.push(x);b[x]=1;a.clear();
    23     while (!q.empty()) {
    24         int u=q.top();q.pop();
    25         a.pb(u);
    26         for (int i=next[u];i;i=edge[i].next) {
    27             if (b[edge[i].to]) continue;
    28             in[edge[i].to]--;
    29             if (in[edge[i].to]==0){
    30                 b[edge[i].to]=1;
    31                 q.push(edge[i].to);
    32             }
    33         }
    34     }
    35 }
    36 int n;
    37 bool iscircle() {
    38     static int q[maxn];
    39     int r=0;
    40     for (int i=1;i<=n;i++) if (in[i]==0) q[++r]=i;
    41     for (int l=1,u=q[l];l<=r;u=q[++l]) 
    42         for (int i=next[u];i;i=edge[i].next){
    43             in[edge[i].to]--;
    44             if (in[edge[i].to]==0) q[++r]=edge[i].to;
    45         }
    46     return r!=n;
    47 }
    48 int cnt,bo[maxn];
    49 bool bfs(int x) {
    50     cnt++;
    51     static int q[maxn];
    52     q[1]=x;
    53     for (int l=1,u=q[1],r=1;l<=r;u=q[++l]) 
    54         for (int i=next[u];i;i=edge[i].next) {
    55             if (b[edge[i].to]) continue;
    56             in[edge[i].to]++;
    57             if (bo[edge[i].to]!=cnt) {
    58                 q[++r]=edge[i].to;
    59                 bo[edge[i].to]=cnt;
    60             }
    61         }
    62 }
    63 int main(){
    64     int T;
    65     scanf("%d",&T);
    66     while (T--) {
    67         int m;
    68         scanf("%d%d",&n,&m);
    69         memset(next,0,sizeof(next));
    70         memset(b,0,sizeof(b));
    71         memset(bo,0,sizeof(bo));
    72         memset(in,0,sizeof(in));
    73         l=0;cnt=0;
    74         for (int i=1;i<=m;i++) {
    75             int x,y;
    76             scanf("%d%d",&x,&y);
    77             addedge(y,x);
    78         }
    79         if (iscircle()) {printf("Impossible!
    ");continue;}
    80         for (int i=1;i<=n;i++) {
    81             if (b[i]) continue;
    82             bfs(i);
    83             tuopu(i);
    84             for (int i=a.size()-1;i+1;i--) printf("%d ",a[i]);
    85         }
    86         printf("
    ");
    87     }
    88     return 0;
    89 }
    View Code

     这几道题是非常的漂亮的,像第一二题的转化真的是想不到啊= =第三题也得有很好的直觉在能做= =

  • 相关阅读:
    蓝桥杯基础练习 杨辉三角形
    蓝桥杯基础练习 回文数 特殊的数字
    普及图论三题 P1807 P1113 P 4017
    P3916 图的遍历
    [转载][总结]图论入门:建图,DFS,BFS,拓扑排序
    如何转载博客园的文章
    P1892 [BOI2003]团伙
    P1621 集合
    [模板]线性筛素数(欧拉筛)
    P5076 普通二叉树(简化版)
  • 原文地址:https://www.cnblogs.com/New-Godess/p/4450078.html
Copyright © 2020-2023  润新知