zoukankan      html  css  js  c++  java
  • 20181031

    orzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjardenorzjarden
    T1 4014: 铃仙的红色之瞳(eyes)

    题目描述

    为了方便你的预测,铃仙对该符卡进行了改造。
    敌方非常强大,可以看作有无限的体力。通过该符卡,铃仙可以释放出子弹,敌方触碰到子弹就会损失一格体力。注意,每次敌方损失体力之后,其位置不会改变。
    当敌方和铃仙 x 坐标相同上时,每秒铃仙损失一点体力(敌方的攻击比较特殊,可以对前后都进行攻击)。注意,这里的秒指的是时间间隔,即第 A 秒时候敌方开始与铃仙处于一条直线上,第 B 秒时候敌方离开这条直线,那么铃仙受到的伤害是(B-A)点。特殊地,如果刚开始铃仙就和敌方在一条直线上,则第 0 秒~第 1 秒也受到一点伤害。若最后铃仙和敌方在 x 坐标相同的位置或者敌方处于有子弹的位置上时,它们只会在第 Q-1 秒到第 Q 秒时受到伤害,并不会在第 Q 秒到第 Q+1 秒受到伤害。
    地图是一个 n*m 的矩形,分别对应的 x 坐标为[1,n],y 坐标为[1,m],给定敌方的初始位置和铃仙的位置(铃仙不会移动),当铃仙发出的子弹超过边界时子弹消失,当敌方越过边界时敌方自动回到初始位置。
    现在有 Q 秒,每秒一次操作,可能是铃仙的操作也可能是敌方的操作,可能存在的操作如下:
    Ins x y 铃仙在(x,y)处召唤了一颗子弹(如果原先就有子弹则该操作无效)
    Del x y 铃仙收回法力,让(x,y)处的子弹消失(如果原先没有子弹则该操作无效)
    MA U 铃仙将所有子弹上移一格
    MA D 铃仙将所有子弹下移一格
    MA L 铃仙将所有子弹左移一格
    MA R 铃仙将所有子弹右移一格
    MB U 敌方上移一格
    MB D 敌方下移一格
    MB L 敌方左移一格
    MB R 敌方右移一格
    现在要你计算 Q 秒后敌方损失的体力和铃仙损失的体力。
    (注:左移指的是横坐标-1,下移指的是纵坐标-1)
    n,m<=100,Q<=1000

    题解

    模拟,走一遍图即可,注意伤害的计算位置(被坑了30 QAQ)
    具体见代码

    #include <bits/stdc++.h>
    using namespace std;
    int Case,n,m,ax,ay,bx,by,cx,cy,Q,t1,t2;
    char c[4],ch;bool a[105][105],b[105][105];
    int main(){
        scanf("%d%d%d%d%d%d%d%d",&Case,&n,&m,&ax,&ay,&bx,&by,&Q);
        cx=bx;cy=by;
        for (int x,y,dx,dy;Q--;){
            if (cx==ax) t2++;if (a[cx][cy]) t1++;scanf("%s",c);
            if (c[0]=='I') scanf("%d%d",&x,&y),a[x][y]=1;
            else if (c[0]=='D') scanf("%d%d",&x,&y),a[x][y]=0;
            else if (c[1]=='A'){
                scanf(" %c",&ch);
                if (ch=='U') dx=0,dy=1;
                if (ch=='D') dx=0,dy=-1;
                if (ch=='L') dx=-1,dy=0;
                if (ch=='R') dx=1,dy=0;
                for (int i=1;i<=n;i++)
                    for (int j=1;j<=m;j++)
                        b[i][j]=a[i-dx][j-dy];
                for (int i=1;i<=n;i++)
                    for (int j=1;j<=m;j++)
                        a[i][j]=b[i][j],b[i][j]=0;
            }
            else{
                scanf(" %c",&ch);
                if (ch=='U') cy++;if (ch=='D') cy--;
                if (ch=='L') cx--;if (ch=='R') cx++;
                if (cx<1 || cx>n || cy<1 || cy>m) cx=bx,cy=by;
            }
        }
        printf("%d
    %d
    ",t1,t2);
        return 0;
    }
    

    T2 4015: 永琳的竹林迷径(path)

    题目描述

    竹林可以看作是一个n 个点的树,每个边有一个边长wi,其中有k 个关键点,永琳需要破坏这些关键点才能走出竹林迷径。
    然而永琳打算将这k 个点编号记录下来,然后随机排列,按这个随机的顺序走过k 个点,但是两点之间她只走最短路线。初始时永琳会施展一次魔法,将自己传送到选定的k 个点中随机后的第一个点。
    现在永琳想知道,她走过路程的期望是多少,答案对998244353 取模。
    n,k<=1e6

    题解

    考虑每条边的贡献
    通过dfs算出在每条边两端的点分别有多少个是属于k的,假设一边有s个,另一边就有k-s个
    对于那s个中的某一个,如果说在走的排列中,它的前一个或者后一个是那k-s个中的一个,那说明这条边就多了一次的贡献
    所以这条边的贡献就是2(ks)/ksw[i]2*(k-s)/k*s*w[i]
    最后相加即可
    具体见代码

    #include <bits/stdc++.h>
    #define _(d) while(d(isdigit(c=getchar())))
    #define I inline
    #define LL long long
    #define E register
    using namespace std;
    I int R(){
        int x;char c;_(!);x=(c^48);
        _()x=(x<<3)+(x<<1)+(c^48);return x;
    }
    const int N=1e6+5,P=998244353;
    int Case,n,t,head[N],nex[N*2],V[N*2],W[N*2],k,top[N],fa[N],dep[N],sz[N],son[N],g[N];
    LL h[N],ans;bool p[N];
    I void add(E int u,E int v,E int w){
        V[++t]=v;W[t]=w;nex[t]=head[u];head[u]=t;
    }
    I void ins(){
        int u=R(),v=R(),w=R();
        add(u,v,w);add(v,u,w);
    }
    I LL K(E LL x,E LL y){
        LL A=1;while(y){
            if (y&1) A=A*x%P;
            x=x*x%P;y>>=1;
        }
        return A;
    }
    I int dfs(E int x,E int fa){
        int s=0,tot=0;
        for (int i=head[x];i;i=nex[i]){
            if (V[i]==fa) continue;
            s=dfs(V[i],x);tot+=s;
            ans=(2ll*s*(k-s)%P*W[i]%P+ans)%P;
        }
        return tot+p[x];
    }
    int main(){
        Case=R();n=R();for (E int i=1;i<n;i++) ins();
        k=R();for (E int i=1;i<=k;i++) p[R()]=1;dfs(1,0);
        return printf("%lld
    ",ans*K(k,P-2)%P),0;
    }
    

    T3 4016: 辉夜的夜空明珠(moon)

    题目描述

    整个回廊可以看作一个n 个点m 条边的无向图,每条边走动花费的时间为1。辉夜、永琳、铃仙、因幡帝等k 个人或兔子可以通过传送阵分别进入这个图上的k 个特殊的点,然后去寻找闯入者。但是在寻找闯入者之前,他们要聚集到一个点,以增强战斗力。注意,可以先到的人停下不走等后来的人。

    闯入者不知道回廊的规则,因此被困住,对辉夜等k 个人的行动没有影响。而辉夜等k个人必须按照回廊的规则走动。

    回廊的规则如下:每个点有一个颜色,一共4 种颜色,红、蓝、黄、绿,分别以R、B、Y、G 表示。走动时必须在第4p+1 步到4p+4 步的时候走四种不同的颜色,当然最后一个不完整的周期内也不能走动相同颜色。注意,起点算第1 步。

    现在给定k 个起点,辉夜想知道他们最短多长时间能够汇合,若不能汇合输出-1。
    n<=50000 m<=200000 k<=10

    题解

    因为k很小,所以我们可以从k下手
    要求最短汇合时间,所以我们可以对那k个点,每个点都去跑一个最短路,最后的答案就是哪个点的最短路的最大值的最小值
    但是这里的最短路是有带限制的,也就是每个周期内的颜色不能相同,但是因为只有4种颜色,所以我们可以设d[i][j]表示到i点,这个周期颜色状态为j的最小值
    直接写bfs就可以过,考场上写了dijstra_heap,也可以过
    具体见代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N=5e4+2,M=4e5+2;
    int head[N],V[M],nex[M],t,Case,n,m,k,p[12],c[N],ans=1e9;
    char ch;bool vis[17][N];int d[17][N],cs[N];
    void add(int u,int v){
        V[++t]=v;nex[t]=head[u];head[u]=t;
    }
    struct O{
        int x,d,g;
        friend bool operator < (const O& A,const O& B){
            return A.d>B.d;
        }
    };
    priority_queue<O>q;
    void work(int x){
        for (int j=0;j<16;j++) for (int i=1;i<=n;i++) d[j][i]=1e9,vis[j][i]=0;
        d[(1<<c[p[x]]-1)][p[x]]=0;q.push((O){p[x],0,(1<<c[p[x]]-1)});
        while(!q.empty()){
            O K=q.top();q.pop();
            if (vis[K.g][K.x]) continue;
            vis[K.g][K.x]=1;
            int r=K.g;if (r==15) r=0;
            for (int i=head[K.x];i;i=nex[i]){
                if (r&(1<<c[V[i]]-1)) continue;
                if (d[r^(1<<c[V[i]]-1)][V[i]]>d[K.g][K.x]+1){
                    d[r^(1<<c[V[i]]-1)][V[i]]=d[K.g][K.x]+1;
                    q.push((O){V[i],d[r^(1<<c[V[i]]-1)][V[i]],r^(1<<c[V[i]]-1)});
                }
            }
        }
        for (int i=1;i<=n;i++){
            int L=1e9;
            for (int j=0;j<16;j++) L=min(L,d[j][i]);
            cs[i]=max(cs[i],L);
        }
    }
    int main(){
        freopen("moon.in","r",stdin);freopen("moon.out","w",stdout);
        scanf("%d%d%d%d",&Case,&n,&m,&k);
        for (int i=1;i<=k;i++) scanf("%d",&p[i]);
        for (int i=1;i<=n;i++){
            scanf(" %c",&ch);
            if (ch=='R') c[i]=1;
            if (ch=='B') c[i]=2;
            if (ch=='Y') c[i]=3;
            if (ch=='G') c[i]=4;
        }
        for (int u,v,i=1;i<=m;i++)
            scanf("%d%d",&u,&v),add(u,v),add(v,u);
        for (int i=1;i<=k;i++) work(i);
        for (int i=1;i<=n;i++) ans=min(cs[i],ans);
        if (ans>=1e9) puts("-1");
        else printf("%d
    ",ans);
        return 0;
    }
    

    总的来说,jarden太强了(rk1的巨佬)

  • 相关阅读:
    使用Docker搭建nginx环境
    使用Docker搭建apache环境
    字符编码-字库表,字符集,字符编码
    go中的sync.pool源码剖析
    JAVA基础语法
    Linux 文件目录管理
    c++ 学习之常用时间函数一览
    MySQL Innodb 中的锁
    MySQL 索引与 B+ 树
    MySQL 表分区操作详解
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/10544715.html
Copyright © 2011-2022 走看看