zoukankan      html  css  js  c++  java
  • cf Round 601

    A.The Two Routes(BFS)

    给出n个城镇,有m条铁路,铁路的补图是公路,汽车和火车同时从1出发,通过每条路的时间为1,不能同时到达除了1和n的其它点,问他们到达n点最少要用多长时间。

    因为是补图,那么一定有一条路是可以直接从1到达n的。
    那么我们把剩下的用bfs求一下即可。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define eps 1e-3
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    int Scan() {
        int res=0, flag=0;
        char ch;
        if((ch=getchar())=='-') flag=1;
        else if(ch>='0'&&ch<='9') res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
        return flag?-res:res;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=405;
    //Code begin...
    
    int n, m, G[N][N], g[N][N], vis[N];
    void bfs(int a[][N])
    {
        queue<int>q;
        q.push(1); vis[1]=0;
        while (!q.empty()) {
            if (vis[n]!=-1) break;
            int u=q.front();
            q.pop();
            FOR(i,1,n) if (a[u][i]&&vis[i]==-1) q.push(i), vis[i]=vis[u]+1;
        }
    }
    int main ()
    {
        int u, v;
        mem(vis,-1);
        scanf("%d%d",&n,&m);
        while (m--) scanf("%d%d",&u,&v), G[u][v]=G[v][u]=1;
        FOR(i,1,n) FOR(j,i+1,n) if (G[i][j]==0) g[i][j]=g[j][i]=1;
        if (G[1][n]==1) bfs(g);
        else bfs(G);
        printf("%d
    ",vis[n]);
        return 0;
    }
    View Code

    B.Lipshitz Sequence(单调队列)

    给出一个序列和q个询问。询问区间的所有子区间的lipshitz的总和是多少。
    lipshitz是指对于区间[l,r], 最大的ceil(|a[i]-a[j]|/i-j).(l<=j<i<=r)。

    数形结合一下,我们画下图可以发现,一个区间[l,r]内的lipshitz一定是由两个相邻的数产生的。
    于是我们把|a[i+1]-a[i]|预处理出来,计算每个值能对结果产生的贡献。
    于是我们需要知道这个值它最左能延伸多少,最右能延伸多少。
    用两个单调队列扫两下就行了。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define eps 1e-3
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    int Scan() {
        int res=0, flag=0;
        char ch;
        if((ch=getchar())=='-') flag=1;
        else if(ch>='0'&&ch<='9') res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
        return flag?-res:res;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=100005;
    //Code begin...
    
    int a[N], b[N], q[N], l[N], r[N], head, tail;
    
    int main ()
    {
        int n, qq, c, d;
        scanf("%d%d",&n,&qq);
        FOR(i,1,n) scanf("%d",a+i);
        FO(i,1,n) b[i]=abs(a[i+1]-a[i]);
        head=1; tail=0;
        FO(i,1,n) {
            while (head<=tail&&b[q[tail]]<=b[i]) tail--;
            l[i]=q[tail]; q[++tail]=i;
        }
        head=1; tail=0; q[tail]=n;
        for (int i=n-1; i>=1; --i) {
            while (head<=tail&&b[q[tail]]<b[i]) tail--;
            r[i]=q[tail]; q[++tail]=i;
        }
        while (qq--) {
            scanf("%d%d",&c,&d);
            LL ans=0;
            FO(i,c,d) {
                int l1=max(c,l[i]+1), r1=min(d-1,r[i]-1);
                ans+=(LL)b[i]*(i-l1+1)*(r1-i+1);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code

    C.Kleofáš and the n-thlon(概率DP)

    有n场比赛,和m名参赛者,已知这n场比赛每个人的rank都不同。
    给出你每场比赛的排名,求最终排名的期望,最终排名是比你rank之和低的人数+1.

    明显的DP,令dp[i][j]表示第i场比赛时分数为j的时候人数的期望。
    那么有dp[i][j]=sum(dp[i-1][k])/(m-1).(j-m<=k<=j-1&&k!=j-a[i]).
    这个复杂度是O(n*m*m)。
    观察发现转移的时候加的是一个区间。我们用前缀和优化转移。
    复杂度O(n*m).

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define eps 1e-3
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    int Scan() {
        int res=0, flag=0;
        char ch;
        if((ch=getchar())=='-') flag=1;
        else if(ch>='0'&&ch<='9') res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
        return flag?-res:res;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=100005;
    //Code begin...
    
    int a[105], flag;
    double dp[2][100005];
    int main ()
    {
        int n, m, sum=0;
        scanf("%d%d",&n,&m);
        FOR(i,1,n) scanf("%d",a+i), sum+=a[i];
        if (m==1) {printf("%.10lf
    ",1.0); return 0;}
        dp[0][0]=m-1;
        FOR(i,1,n) {
            flag^=1;
            mem(dp[flag],0);
            FOR(j,i,i*m) {
                int l=max(j-m,i-1), r=min(j-1,(i-1)*m);
                dp[flag][j]=dp[flag^1][r]-(l==0?0:dp[flag^1][l-1]);
                int k=j-a[i];
                if (k>=l&&k<=r) dp[flag][j]-=(dp[flag^1][k]-(k==0?0:dp[flag^1][k-1]));
                dp[flag][j]/=(m-1);
            }
            FOR(j,i,i*m) dp[flag][j]+=dp[flag][j-1];
        }
        double ans=(dp[flag][sum-1]-dp[flag][n-1]);
        printf("%.10lf
    ",ans+1);
        return 0;
    }
    View Code

    D.Acyclic Organic Compounds(Trie树合并)

    我们算出每个节点的dif,这需要用到trie树的合并操作。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define eps 1e-3
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    int Scan() {
        int res=0, flag=0;
        char ch;
        if((ch=getchar())=='-') flag=1;
        else if(ch>='0'&&ch<='9') res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
        return flag?-res:res;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=300005;
    //Code begin...
    
    struct Edge{int p, next;}edge[N<<1];
    int head[N], cnt=1, val[N], ch[N*15][27], tot, size[N*15];
    char s[N];
    
    void add_edge(int u, int v)
    {
        edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++;
    }
    int merge(int u, int v)
    {
        if (u<0) return v;
        if (v<0) return u;
        int t=++tot;
        size[t]=1;
        FOR(i,1,26) {
            ch[t][i]=merge(ch[u][i], ch[v][i]);
            if (ch[t][i]>=0) size[t]+=size[ch[t][i]];
        }
        return t;
    }
    void dfs(int x, int fa)
    {
        FOR(i,1,26) ch[x][i]=-1;
        for (int i=head[x]; i; i=edge[i].next) {
            int v=edge[i].p;
            if (v==fa) continue;
            dfs(v,x);
            int lab=s[v]-'a'+1;
            ch[x][lab]=merge(ch[x][lab],v);
        }
        size[x]=1;
        FOR(i,1,26) if (ch[x][i]>=0) size[x]+=size[ch[x][i]];
        val[x]+=size[x];
    }
    int main ()
    {
        int n, u, v;
        scanf("%d",&n);
        FOR(i,1,n) scanf("%d",val+i);
        scanf("%s",s+1);
        FO(i,1,n) scanf("%d%d",&u,&v), add_edge(u,v), add_edge(v,u);
        tot=n;
        dfs(1,0);
        int ma=0, ans=0;
        FOR(i,1,n) ma=max(val[i],ma);
        FOR(i,1,n) if (ma==val[i]) ans++;
        printf("%d
    %d
    ",ma,ans);
        return 0;
    }
    View Code

    E.A Museum Robbery(待填坑)

  • 相关阅读:
    (转)MVC 与三层架构
    (转)CentOS一键安装Nginx脚本
    (转)Python异常类的继承关系
    CMFCPropertyGridProperty用法
    C语言终极面试及答案分析
    C/C++函数指针(typedef简化定义)
    UNIX 家族及Linux
    Socket的综合应用总结
    Socket模型(二):完成端口(IOCP)
    socket通信中select函数的使用和解释
  • 原文地址:https://www.cnblogs.com/lishiyao/p/6262010.html
Copyright © 2011-2022 走看看