• 「BJOI2019」


    #4372. 「BJOI2019」排兵布阵

    题目描述:

    小 C 正在玩一款排兵布阵的游戏。在游戏中有 $n$ 座城堡,每局对战由两名玩家来争夺这些城堡。每名玩家有 $m$ 名士兵,可以向第 $i$ 座城堡派遣 $a_i$ 名士兵去争夺这个城堡,使得总士兵数不超过 $m$。

    如果一名玩家向第 $i$ 座城堡派遣的士兵数严格大于对手派遣士兵数的两倍,那么这名玩家就占领了这座城堡,获得 $i$ 分。

    现在小 C 即将和其他 $s$ 名玩家两两对战,这 $s$ 场对决的派遣士兵方案必须相同。小 C 通过某些途径得知了其他 $s$ 名玩家即将使用的策略,他想知道他应该使用什么策略来最大化自己的总分。

    由于答案可能不唯一,你只需要输出小 C 总分的最大值。

     思路:

    背包问题

    $f_{i,j}$ 表示选到前 $i$ 座城堡已经用了 $j$ 个士兵所能获得总分的最大值。

    倘若直接枚举每座城堡派几个士兵效率是 $O(nm^{2})$ ,但是我们发现只有多获胜一个人才能使总分增多,所以我们可以考虑枚举每座城堡赢几个人,效率变成 $O(nms)$ 。

     代码:

    #include<bits/stdc++.h>
    #define il inline
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=105,M=2e4+5;
    int n,s,m,a[N][N],f[M];
    il int read(){
       int x,f=1;char ch;
       _(!)ch=='-'?f=-1:f;x=ch^48;
       _()x=(x<<1)+(x<<3)+(ch^48);
       return f*x;
    }
    int main()
    {
        s=read();n=read();m=read();
        for(int i=1;i<=s;i++)for(int j=1;j<=n;j++)a[j][i]=read()*2+1;
        for(int i=1;i<=n;i++)sort(a[i]+1,a[i]+1+s);
        for(int i=1;i<=n;i++)for(int j=m-1;j>=0;j--){
            for(int k=1;k<=s;k++){
                if(a[i][k]+j>m)break;
                f[a[i][k]+j]=max(f[a[i][k]+j],f[j]+k*i);
            }
        }
        int ans=0;
        for(int i=1;i<=m;i++)ans=max(ans,f[i]);
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    #4374. 「BJOI2019」光线

    题目描述:

    当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收。

    设对于任意 $x$,有 $x imes a_i\%$ 单位的光会穿过它,有 $x imes b_i\%$ 的会被反射回去。

    现在 $n$ 层玻璃叠在一起,有 $1$ 单位的光打到第 $1$ 层玻璃上,那么有多少单位的光能穿过所有 $n$ 层玻璃呢?

     思路:

    $dp$ 问题

    令 $f_{i}$ 表示 $1$ 单位光射入第 $i$ 层玻璃,能有多少穿过 $n$ 层玻璃。

    令 $g_{i}$ 表示 $1$ 单位的光射入第 $i$ 层玻璃,最终能有多少光反射出去。
    $$
    f_{i}=a_i*(f_{i+1}+g_{i+1}*b_{i}*f_{i+1}+...)
    $$

    $$
    f_{i}=a_i*f_{i+1}*frac{1}{1-b_i*g_{i+1}}
    $$

    $$
    gi=b_i+a_i*g_{i+1}*a_{i}+a_i*g_{i+1}*b_{i}*g_{i+1}*a_{i}...
    $$

    $$
    g_{i}=b_i+a_i^2*g_{i+1}*frac{1}{1-b_i*g_{i+1}}
    $$

     代码:

    #include<bits/stdc++.h>
    #define il inline
    #define LL long long
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=5e5+5,p=1e9+7,ny=570000004;
    int n,a[N],b[N],f[N],g[N];
    il int read(){
       int x,f=1;char ch;
       _(!)ch=='-'?f=-1:f;x=ch^48;
       _()x=(x<<1)+(x<<3)+(ch^48);
       return f*x;
    }
    il int ksm(LL a,int y){
        LL b=1;
        while(y){
            if(y&1)b=b*a%p;
            a=a*a%p;y>>=1;
        }
        return b;
    }
    il int mu(int x,int y){
        return (x+y>=p)?x+y-p:x+y;
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++){
            a[i]=1ll*read()*ny%p;b[i]=1ll*read()*ny%p;
        }
        f[n]=a[n];g[n]=b[n];
        for(int i=n-1;i;i--){
            f[i]=1ll*a[i]*f[i+1]%p*ksm(mu(1,p-1ll*g[i+1]*b[i]%p),p-2)%p;
            g[i]=mu(b[i],1ll*a[i]*a[i]%p*g[i+1]%p*ksm(mu(1,p-1ll*b[i]*g[i+1]%p),p-2)%p);
        }
        printf("%d
    ",f[1]);
        return 0;
    }
    View Code

    #4375. 「BJOI2019」删数

    题目描述:

    对于任意一个数列,如果能在有限次进行下列删数操作后将其删为空数列,则称这个数列可以删空。一次删数操作定义如下:

    - 记当前数列长度为 $k$,则删掉数列中所有等于 $k$ 的数。

    现有一个长度为 $n$ 的数列 $a$,有 $m$ 次修改操作,第 $i$ 次修改后你要回答:经过 $i$ 次修改后的数列 $a$,至少还需要修改几个数才可删空?

    每次修改操作为单点修改或数列整体加一或数列整体减一。

    思路:

    对于一个数 $x$ 共有 $b[x]$ 个,那么他所能覆盖的区间为 $[x-b[x]+1,x]$ ,答案即为区间内没有被覆盖的数。

    对于整体加减相当于把被覆盖区间范围整体移动。

    可以用线段树维护。

     代码:

    #include<bits/stdc++.h>
    #define il inline
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=6e5+5;
    int n,m,a[N],ans,mx,b[N],fir,mn[N<<2],num[N<<2],tag[N<<2];
    il int read(){
       int x,f=1;char ch;
       _(!)ch=='-'?f=-1:f;x=ch^48;
       _()x=(x<<1)+(x<<3)+(ch^48);
       return f*x;
    }
    il void update(int x){
        mn[x]=min(mn[x<<1],mn[x<<1|1]);
        num[x]=(mn[x]==mn[x<<1]?num[x<<1]:0)+(mn[x]==mn[x<<1|1]?num[x<<1|1]:0);
    }
    il void pushdown(int x){
        if(!tag[x])return;
        int v=tag[x];tag[x]=0;
        mn[x<<1]+=v;mn[x<<1|1]+=v;tag[x<<1]+=v;tag[x<<1|1]+=v;
    }
    il void build(int x,int l,int r){
        num[x]=r-l+1;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    }
    il void change(int x,int l,int r,int ql,int qr,int v){
        if(ql<=l&&r<=qr){
            tag[x]+=v;mn[x]+=v;
            return;
        }
        int mid=(l+r)>>1;pushdown(x);
        if(ql<=mid)change(x<<1,l,mid,ql,qr,v);
        if(mid<qr)change(x<<1|1,mid+1,r,ql,qr,v);
        update(x);
    }
    il int query(int x,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr){
            if(mn[x]==0)return num[x];
            else return 0;
        }
        int res=0,mid=(l+r)>>1;pushdown(x);
        if(ql<=mid)res=query(x<<1,l,mid,ql,qr);
        if(mid<qr)res+=query(x<<1|1,mid+1,r,ql,qr);
        return res;
    }
    int main()
    {
        n=read();m=read();
        mx=2*(n+m);fir=n+m;build(1,1,mx);
        for(int i=1;i<=n;i++)a[i]=read()+fir,b[a[i]]++;
        for(int i=fir+1;i<=fir+n;i++)if(b[i])change(1,1,mx,i-b[i]+1,i,1);
        for(int i=1;i<=m;i++){
            int p=read(),x=read();
            if(!p){
                if(x==1){
                    if(b[fir+n])change(1,1,mx,fir+n-b[fir+n]+1,fir+n,-1);
                    fir--;
                    if(b[fir+1])change(1,1,mx,fir+1-b[fir+1]+1,fir+1,1);
                }
                else{
                    if(b[fir+1])change(1,1,mx,fir+1-b[fir+1]+1,fir+1,-1);
                    fir++;
                    if(b[fir+n])change(1,1,mx,fir+n-b[fir+n]+1,fir+n,1);
                }
            }
            else{
                int now=a[p];
                if(now<=fir+n&&now>fir)change(1,1,mx,now-b[now]+1,now-b[now]+1,-1);b[now]--;
                now=fir+x;b[now]++;a[p]=now;
                if(now<=fir+n&&now>fir)change(1,1,mx,now-b[now]+1,now-b[now]+1,1);
            }
            printf("%d
    ",query(1,1,mx,fir+1,fir+n));
        }
        return 0;
    }
    View Code

    #4369. 「BJOI2019」奥术神杖

    题目:

    Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的神器,试图借助神器的神秘力量帮助她们战胜地灾军团。

    在付出了惨痛的代价后,精灵们从步步凶险的远古战场取回了一件保存尚完好的神杖。但在经历过那场所有史书都视为禁忌的“诸神黄昏之战”后,神杖上镶嵌的奥术宝石已经残缺,神力也几乎消耗殆尽。精灵高层在至高会议中决定以举国之力收集残存至今的奥术宝石,并重金悬赏天下能工巧匠修复这件神杖。

    你作为神术一脉第五百零一位传人,接受了这个艰巨而神圣的使命。 神杖上从左到右镶嵌了 $n$ 颗奥术宝石,奥术宝石一共有 $10$ 种,用数字 `0123456789` 表示。有些位置的宝石已经残缺,用 `.` 表示,你需要用完好的奥术宝石填补每一处残缺的部分(每种奥术宝石个数不限,且不能够更换未残缺的宝石)。古老的魔法书上记载了 $m$ 种咒语 $(S_i,V_i)$,其中 $S_i$ 是一个非空数字串,$V_i$ 是这种组合能够激发的神力。

    神杖的初始神力值 $mathrm{Magic} = 1$,每当神杖中出现了连续一段宝石与 $S_i$ 相等时,神力值 $mathrm{Magic}$ 就会乘以 $V_i$。但神杖如果包含了太多咒语就不再纯净导致神力降低:设 $c$ 为神杖包含的咒语个数(若咒语类别相同但出现位置不同视为多次),神杖最终的神力值为 $sqrt[c]{mathrm{Magic}}$。(若 $c = 0$ 则神杖最终神力值为 $1$。)

    例如有两种咒语 $(01,3)$ 、$(10,4)$,那么神杖 `0101` 的神力值为 $sqrt[3]{ 3 imes 4 imes 3}$。

    你需要使修复好的神杖的最终的神力值最大,输出任何一个解即可。

    思路:

    第一部的转换还是挺妙妙的
    $$
    val=sqrt[c]{prod_{i=1}^{c} V_{t_i}}
    $$
    如果对权值取对数
    $$
    ln^{val}=frac{sum_{i=1}^{c}V_{ti}}{c}
    $$
    这就是典型的分数规划了

    至少在 $ac$ 自动机上跑 $dp$ 。效率是 $O(sn)$ 。

     代码:

    #include<bits/stdc++.h>
    #define il inline
    #define db double
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=1505;
    const db eps=1e-7;
    int n,m,ch[N][11],cnt=1,num[N],fa[N];
    db val[N],eg[N],f[N][N];
    char s[N],t[N],res;
    struct node{
        int x,y,tp;
    }fr[N][N];
    il int read(){
       int x,f=1;char ch;
       _(!)ch=='-'?f=-1:f;x=ch^48;
       _()x=(x<<1)+(x<<3)+(ch^48);
       return f*x;
    }
    il void insert(db v){
        int x=1,l=strlen(t+1);
        for(int i=1;i<=l;i++){
            if(!ch[x][t[i]-'0'])ch[x][t[i]-'0']=++cnt;
            x=ch[x][t[i]-'0'];
        }
        num[x]++;val[x]+=v;
    }
    il void getfail(){
        queue<int> q;fa[1]=1;
        for(int i=0;i<10;i++){
            if(!ch[1][i])ch[1][i]=1;
            else q.push(ch[1][i]),fa[ch[1][i]]=1;
        }
        while(!q.empty()){
            int x=q.front();q.pop();
            val[x]+=val[fa[x]];num[x]+=num[fa[x]];
            for(int i=0;i<10;i++){
                if(!ch[x][i])ch[x][i]=ch[fa[x]][i];
                else{
                    fa[ch[x][i]]=ch[fa[x]][i];
                    q.push(ch[x][i]);
                }
            }
        }
    }
    il bool pd(db m){
        for(int i=1;i<=cnt;i++)eg[i]=m*num[i]-val[i];
        for(int i=0;i<=n;i++)for(int j=1;j<=cnt;j++)f[i][j]=1e9;
        f[0][1]=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=cnt;j++){
                if(f[i-1][j]>1e6)continue;
                if(s[i]=='.'){
                    for(int k=0;k<10;k++){
                        if(f[i-1][j]+eg[ch[j][k]]<f[i][ch[j][k]]){
                            f[i][ch[j][k]]=f[i-1][j]+eg[ch[j][k]];
                            fr[i][ch[j][k]]=(node){i-1,j,k};
                        }
                    }
                }
                else{
                    int k=s[i]-'0';
                    if(f[i-1][j]+eg[ch[j][k]]<f[i][ch[j][k]]){
                        f[i][ch[j][k]]=f[i-1][j]+eg[ch[j][k]];
                        fr[i][ch[j][k]]=(node){i-1,j,k};
                    }
                }
            }
        }
        for(int i=1;i<=cnt;i++)if(f[n][i]<0)return 1;
        return 0;
    }
    il void back(int x,int y){
        if(!x)return;
        back(x-1,fr[x][y].y);
        printf("%c",fr[x][y].tp+'0');
    }
    int main()
    {
        n=read();m=read();
        scanf(" %s",s+1);
        for(int i=1;i<=m;i++){
            scanf(" %s",t+1);
            db x=read();x=log2(x);
            insert(x);
        }
        getfail();
        db l=0,r=100;
        while(r-l>eps){
            db mid=(l+r)/2.0;
            if(pd(mid))l=mid;
            else r=mid;
        }
        pd(l);//cout<<l<<endl;
        for(int i=1;i<=cnt;i++)if(f[n][i]<0){
            back(n,i);break;
        }
        puts("");
        return 0;
    }
    View Code
  • 相关阅读:
    分分钟用上C#中的委托和事件
    AutoResetEvent详解
    C#跨线程调用
    多线程编程的注意事项
    C#中WinForm程序退出方法技巧总结
    用c#实现单链表(程序代码已经验证,完全正确)
    event & EventHandler
    Kubernetes理论02
    centos7 日志文件
    CentOS7 FTP安装与配置
  • 原文地址:https://www.cnblogs.com/Jessie-/p/11007871.html
Copyright © 2020-2023  润新知