zoukankan      html  css  js  c++  java
  • contest20191023

    slz的题 KCN

    雨中的晴天

    宫水三叶生活的城市是一个一维平面上的城市。三叶喜欢用一个长度为n的线段来表示这座城市。线段上(包含端点)平均分布着 $n+1$ 个点,其中第 $i$ 个点到第 $i+1$ 个点视为第 $i$ 个区。

    最近,这座城市不断的下雨,一直没有放晴,所有人都在期待的晴天。不同的区对晴天的渴望度不一样。三叶通过统计,将第 $i$ 个区的人对晴天的渴望度形式化成 $s_i$ 。

    终于,这座城市迎来了久违的晴天。但是晴天的范围没有覆盖整个城市,而是从 $n+1$ 个点中的某一个出发,向往扩散 $d$ 个区。

    在晴天下的人们非常开心。形式化的,如果第 $i$ 个区在晴天的覆盖范围内,并且和晴天中心还隔着 $x$ 个区,那么这个区的人的开心值为 $(d-x)^2 cdot s_i$ 。这个城市的开心值为每一个区的开心值之和。

    虽然晴天的地点已经固定了,但是三叶还是想知道如果晴天的地点可以任选,那么最后城市的开心值最大是多少?

    sol

    有两段,可以分开考虑

    每一段形如$  s_i imes 1+s_{i+1} imes 4+s_{i+2} imes 9+...+s_{i+d-1} imes d^2 $

    往前移动时,更新的值与原来的值差形如 $ sum 2 imes (i+x) imes s_i$ x为常数

    预处理维护即可。

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 2000006
    #define _(d) while(d(isdigit(ch=getchar())))
    #define ll long long
    using namespace std;
    ll n,s[maxn],d;
    ll sum[maxn],s1[maxn],s2[maxn],a1,a2,ans,S,T;
    ll R(){
        ll v,f=1;char ch;_(!)if(ch=='-')f=-1;
        v=(ch^48);_()v=(v<<1)+(v<<3)+(ch^48);
        return v*f;
    }
    int main()
    {
        n=R();d=R();
        for(ll i=d+1;i<=d+n;i++)s[i]=R();
        n=n+d+d;
        for(ll i=1;i<=n;i++)sum[i]=sum[i-1]+s[i],s1[i]=s1[i-1]+1LL*i*s[i];
        for(ll i=n;i>=1;i--)s2[i]=s2[i+1]+1LL*(n-i+1)*s[i];
        for(ll i=1;i<=d;i++)a1+=s[i]*i*i;
        for(ll i=d+1,j=d;i<=d+d;i++,j--)a2+=s[i]*j*j;
        ans=max(ans,a1+a2);
        for(ll i=2;i<=n-d-d;i++){
            ll m=i+d-1;
            a1=a1-s[i-1]+s[m]*d*d;
            S=sum[m-1]-sum[i-1];
            T=(s1[m-1]-s1[i-1])-(i-1)*S;
            a1=a1-S-2*T;
            
            a2=a2-s[m]*d*d+s[m+d];
            S=sum[m+d-1]-sum[m];
            T=(s2[m+1]-s2[m+d])-S*(n-m-d+1);
            a2=a2+S+2*T;
            ans=max(ans,a1+a2);
        }
        cout<<ans<<endl;
        return 0;
    }

    燃烧的火焰

    宫水三叶擅长手工,她自己编织了一张网。

    这张网可以用一个 $n$ 个点 $m$ 条边的连通图来表示,每一条边都有长度。

    但是这张网毕竟是可燃物。某一天,网上的 $k$ 个节点在 $0$ 时刻突然同时被点燃了,火焰以单位速度沿着边向外扩散。具体来说,如果有一条长度为 $l$ 的边连接着点 $x,y$ ,假设第 $i$个 时刻 $x$ 节点被点燃了,那么在 $i+l$ 的时刻 $y$ 节点也会被点燃。反之也是成立的。

    如果整张图的 $n$ 个节点全部被点燃了,那么就认为这张图完全被点燃了。

    既然着火了,那么首要任务就是救火。三叶请小`H`来帮忙。在 $0$ 时刻时,小`H`随机选择了若干个已经被点燃的点,将它们扑灭。但是,小`H`扑灭了那些点后并没有使整张图完全被点燃的时间推晚!

    三叶觉得小`H`运气太差了,于是她想知道这个事件的概率。

    形式化的说,小`H`有 $2^k$ 种灭火方案(包含一个都不选)。假设小`H`随机从中选一种,有多少概率选到的灭火方案没能使整张图完全被点燃的时间推晚。

    假设在没有灭火时整张图完全被点燃从时刻 $a$ 开始,灭火后整张图完全被点燃从时刻 $b$ 开始,而没能使整张图完全被点燃的时间推晚的方案当且仅当 $a=b$ 。

    sol

    多源最短路求出每一个点到任意一个着火点的最短距离,即为该点被点燃的时间。

    记所有被点燃的最晚时间为Max

    考虑一个非法方案,该方案一定会把到某点距离小于等于Max的着火点全部扑灭。

    那么可以得到点集S,S的所有超集都是非法方案。

    考虑dp f[S]|=f[S-(1<<i)] 

    效率2^n*n+nlogn

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define maxn 100005
    #define inf 1e16
    #define ll long long 
    #define mod 998244353
    using namespace std;
    int n,m,num,s[22],f[1<<22],head[maxn],tot;
    int flag[maxn];
    ll d[maxn],dis[maxn][22],M[maxn],Max,ans;
    struct node{
        int v,w,nex;
    }e[maxn*4];
    struct no{
        int x;ll dist;
    };
    bool operator <(no A,no B){return A.dist>B.dist;}
    void add(int t1,int t2,int t3){
        e[++tot].v=t2;e[tot].w=t3;e[tot].nex=head[t1];head[t1]=tot;    
    }
    void dij(int S,int id){
        priority_queue<no>q;
        for(int i=1;i<=n;i++)d[i]=inf,flag[i]=0;
        q.push((no){S,0});d[S]=0;
        while(!q.empty()){
            no k=q.top();q.pop();
            if(flag[k.x])continue;
            flag[k.x]=1;
            for(int i=head[k.x];i;i=e[i].nex){
                if(d[e[i].v]>d[k.x]+e[i].w){
                    d[e[i].v]=d[k.x]+e[i].w;
                    q.push((no){e[i].v,d[e[i].v]});
                }
            }
        }
        for(int i=1;i<=n;i++)dis[i][id]=d[i],M[i]=min(M[i],d[i]);
    }
    ll work(ll a,ll N){
        ll A=1;for(;N;N>>=1,a=a*a%mod)if(N&1)A=A*a%mod;return A;
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&num);
        for(int i=1;i<=num;i++)scanf("%d",&s[i]);
        for(int i=1,t1,t2,t3;i<=m;i++){
            scanf("%d%d%d",&t1,&t2,&t3);
            add(t1,t2,t3);add(t2,t1,t3);
        }
        for(int i=1;i<=n;i++)M[i]=inf;
        for(int i=1;i<=num;i++)dij(s[i],i);
        for(int i=1;i<=n;i++)Max=max(Max,M[i]);
        int Al=(1<<num)-1;
        for(int i=1;i<=n;i++){
            int t=0;
            for(int j=1;j<=num;j++){
                if(dis[i][j]<=Max)t|=(1<<(j-1));
            }
            int S=(Al^t);
            f[S]=1;
        }
        for(int i=Al;i;i--){
            for(int j=1;j<=num;j++){
                f[i]|=f[i|(1<<(j-1))];
            }
        }
        for(int i=1;i<=Al;i++)ans+=f[i];
        ans++;
        ll A=work(work(2,num),mod-2);
        ans=ans*A%mod;ans=(1-ans+mod)%mod;
    
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    Lua 学习之基础篇一<Lua 运算符>
    Git: invalid active developer path
    Lua中使用continue 小练习
    Xcode 运行objc_msgSend 提示objc_msgsend()Too many arguments to function call, expected 0
    逆向思维
    机场
    旅行者
    好图计数
    支配树
    一般图最大匹配
  • 原文地址:https://www.cnblogs.com/liankewei/p/11729052.html
Copyright © 2011-2022 走看看