• 校内集训20180920


    $T1:$(Loj2333

    铁路沿线$N$个车站,车分三种:快,慢,次快车。慢车走1个站花$A$单位时间,每站都停;快车走1个站花费$B$单位时间,只在$M$个站停,停靠站输入给出(起点$1$和终点$N$必停);次快车走1个站花费$C$单位时间,一共在$K$个站停,且必须在快车停靠站停,剩下$K-M$个停靠站随意建造。速度$A,B,C$满足$B<C<A$。求如何建造次快车停靠站使得在$T$分钟内能到达的车站尽量多。(所有移动均为单向,$1->N$方向)

    (到达:停靠在此站。每个车站单独计数,即统计有几个车站从$1$走到该车站花费$T$分钟以内。)

    $Nleq 10^9,Mleq Kleq 3000$。

    题解:

    第一遍看根本没看懂,$JOI$考的都是读题能力么……

    看懂的话应该很快发现由于$B<C<A$,整个图被快车站分成了$M-1$个块。

    修建的任意一个次快车站只能影响到它所在的块内在它后面的车站。

    (块外的车站可以通过快车走到,并且不影响次快车在该块内的修建(所有快车停靠站都是次快车停靠站)为什么还要走次快车?)

    显然,已知速度,时间,每个块内修建$k$个次快车站的贡献是可以计算的。

    那么即可得到$O(M imes K^2)$的$dp$,$dp[i][j]$表示处理到第$i$个块,一共修建了$j$个次快车站时能到达的最多车站。

    枚举该块内修建了$k$个转移即可。

    好像过不了,考虑优化。

    容易发现一个块内每放一个车站的贡献值是递减的。($V$不变,$T$减少,$S$便减少)

    由此产生一个很重要的推论:一个块内按贡献值从大到小排序依次修建,一定是合法的。

    (不会出现一个块内修建第$k$个的贡献比第$k-j$个贡献大的情况,否则你没修建到第$k-j$个怎么修建第$k$个?)

    那么既然每个块互不影响,所有块均满足该推论。

    于是可以将所有块内修建第$i$个块的贡献值扔到一个优先队列里,每次操作取出队首,在此修建,累加答案,并将其出队。操作$k$次得到答案。

    复杂度$O(K imes log(M imes K))$。

    这题想了$30min$,标程写了$1h-$,对拍写了$2h+$写挂了,最后直接交标程$A$了,我尼玛……

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    
    using namespace std;
    #define MAXN 3005
    #define MAXM 500005
    #define INF 0x7fffffff
    #define ll long long
    
    priority_queue<ll> q;
    ll S[MAXN],sgo[MAXN][MAXN];
    inline ll read(){
        ll x=0,f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar())
            if(c=='-')
                f=-1;
        for(;isdigit(c);c=getchar())
            x=x*10+c-'0';
        return x*f;
    }
    
    int main(){
        ll N=read(),M=read(),K=read();K-=M;
        ll A=read(),B=read(),C=read(),T=read();
        for(ll i=1;i<=M;i++) S[i]=read();
        sort(S+1,S+1+M);
        for(ll i=1;i<=M;i++){
            if(i==1) continue;
            //cout<<i<<endl;
            ll slen=S[i-1]-1;ll stim=T-(slen*B);
            //cout<<stim<<endl;
            if(stim<0) break;
            //cout<<stim<<endl;
            sgo[i][0]=stim/A;
            ll sum=sgo[i][0];
            //cout<<sum<<":"<<S[i-1]<<":"<<S[i]<<endl;
            if(sum+S[i-1]>=S[i]){
                sgo[i][0]-=(sum+S[i-1]-S[i]+1);
                sgo[i][0]=max(sgo[i][0],(ll)0);
                //cout<<i<<":"<<sgo[i][0]<<" ";
                continue;
            }
            //cout<<i<<":"<<sgo[i][0]<<" ";
            for(ll j=1;j<=K;j++){
                if(stim<(sum+1)*C) break; 
                sgo[i][j]=(stim-(sum+1)*C)/A+1;
                sum+=sgo[i][j];
                if(sum+S[i-1]>=S[i]){
                    sgo[i][j]-=(sum+S[i-1]-S[i]+1);
                    sgo[i][j]=max(sgo[i][j],(ll)0);
                    //cout<<sgo[i][j]<<" ";
                    break;
                }
                //cout<<sgo[i][j]<<" ";
            }
            //cout<<endl;
        }
        ll ans=0;
        for(ll i=2;i<=M;i++){
            if((S[i]-1)*B>T) break;
            ans++;
        }
        //cout<<ans<<endl;
        for(ll i=1;i<=M;i++){
            //cout<<i<<":"<<sgo[i][0]<<endl;
            ans+=sgo[i][0];
            //cout<<ans<<endl;
        }
        //cout<<ans<<endl;
        for(ll i=1;i<=M;i++)
            for(ll j=1;j<=K;j++)
                q.push(sgo[i][j]);
        for(ll i=1;i<=K;i++){ans+=q.top();q.pop();}
        printf("%lld
    ",ans);
        //cout<<ans<<endl;
        /*
        for(ll i=1;i<=M;i++){
            if(S[i]==1) continue;
            ll slen=S[i-1]-1;ll stim=slen*B;
            ll st=T-stim;ll sgo[0]=st/A,cnt=0;
            if(st<0) break;
            for(ll k=0;k<=K;k++) dp[i][k]=dp[i-1][k]+sgo[0]+1;
            ll num=sgo[0];
            if(num>=S[i]-S[i-1]-1) continue;
            for(ll k=1;k<=K;k++){
                sgo[k]=(st-(sgo[i-1]*C))/A;
                num+=sgo[k],cnt++;
                if()
            }
            for(ll k=1;k<=K;k++){
                for(ll l=1;l<=k;l++){
                    
                    sgo=
                    dp[i][k]=dp[i-1][k]+
                }
            }
        }*/
        return 0;
    }
    /*
    12 3 4
    10 1 2
    30
    1
    11
    12
    */

    T2(Loj2334):

    给你一个$N imes M$的矩阵,将其划分成两块使得两块中的极差($max-min$)最大者最小。划分不能出现“突出”或“凹陷”。

    原句:对于每一行/列,如果我们将这一行/列单独取出,这一行/列里同省的任意两个区块互相连接。这一行/列内的所有区块可以全部属于一个块。

    $N,Mleq 2000$。

    题解:

    看懂了非常好做,考点依旧是读题。

    根据题意第一个国家只可能处在第二个的左上,右上,左下,右下。

    那么每个方向二分答案求解即可。

    但如果看了上一题的时间花费就知道我已经没时间写这题了……

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    
    using namespace std;
    #define MAXN 3005
    #define MAXM 500005
    #define INF 0x7fffffff
    #define ll long long
    
    int N,M,maxn,minn;
    int A[MAXN][MAXN];
    int tmp[MAXN][MAXN];
    inline int read(){
        int x=0,f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar())
            if(c=='-')
                f=-1;
        for(;isdigit(c);c=getchar())
            x=x*10+c-'0';
        return x*f;
    }
    
    bool check(int x){
        int pos=M;
        for(int i=1;i<=N;i++){
            for(int j=1;j<=pos;j++)
                if(A[i][j]-minn>x)
                    {pos=j-1;break;}
            for(int j=pos+1;j<=M;j++)    
                if(maxn-A[i][j]>x) 
                    return 0;
        }
        return 1;
    }
    
    void sswap(){
        for(int i=1;i<=N;i++)
            for(int j=1;j<=M;j++)
                tmp[j][N-i+1]=A[i][j];
        for(int i=1;i<=M;i++)
            for(int j=1;j<=N;j++)
                A[i][j]=tmp[i][j];
        return;    
    }
    
    int main(){
        N=read(),M=read();
        maxn=-INF,minn=INF;
        for(int i=1;i<=N;i++)
            for(int j=1;j<=M;j++){
                A[i][j]=read();
                maxn=max(maxn,A[i][j]);
                minn=min(minn,A[i][j]);
            }
        int mans=INF;
        for(int i=1;i<=4;i++){
            int l=0,r=maxn-minn,ans=-INF;
            while(l<=r){
                int mid=(l+r)>>1;
                if(check(mid)) ans=mid,r=mid-1;
                else l=mid+1;
            }
            mans=min(ans,mans);
            sswap();swap(N,M);
        }
        printf("%d
    ",mans);
        return 0;
        
    }

    T3(Loj2325):

    bzoj4832升级版,攻击次数从$50$变为$10^{18}$(炉石传说没有外挂),求期望对$998244353$取模的值。

    题解:

    弱化版题目没什么问题吧……不管用什么奇怪的顺序转移应该都是能$A$的。

    多说一句,如果直接预处理$dp[i][j][k][l]$表示还剩$i$次攻击,剩余$1,2,3$血奴隶主的个数分别为$j,k,l$个,

    每次从还剩$i-1$次攻击转移过来(也就是反向建拓扑图)的话,可以通过$T$极大的数据。

    然后我们发现这个题的攻击次数是$10^{18}$。

    (一回合打$50$火妖法还能够到(还把我超生德直接打死),但这尼玛$10^{18}$难不成要无限回合火球法?)

    再枚举$N$进行转移显然不可取,所以进行矩阵优化。

    容易发现总状态数为固定的$165$个。(模型:$0,1,2,3$每种$k$个和为$7$,$k$可以为$0$)

    那么我们将所有状态排成一列,形成一个$1 imes 165$的初始矩阵。

    状态间互相转移的路径是相同的,每次转移的概率也是相同的,

    那么可以构造一个$165 imes 165$的转移矩阵,答案相当于${初始矩阵 imes (转移矩阵^N)}$。

    使用矩阵快速幂即可。(需要卡常)

    但$165 imes 165$不好维护答案,再加$1$维变为$166 imes 166$即可维护打脸期望。

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    
    using namespace std;
    #define MAXN 100005
    #define MAXM 10
    #define MAXK 170
    #define MAXL 63
    #define INF 0x7fffffff
    #define ll long long
    
    const ll MOD=998244353;
    const ll mod=(0x7fffffffffffffffll/MOD-MOD)*MOD;
    ll inv[MAXK],sta[MAXM][MAXM][MAXM],res[MAXK],tmp[MAXK],num;
    struct Matrix{
        ll A[MAXK][MAXK];
        Matrix() {memset(A,0,sizeof(A));}
    }m[MAXL+5];
    
    inline ll read(){
        ll x=0,f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar())
            if(c=='-')
                f=-1;
        for(;isdigit(c);c=getchar())
            x=x*10+c-'0';
        return x*f;
    }
    
    inline ll power(ll a,ll b){
        ll ans=1;
        while(b){
            if(b&1) ans*=a%MOD,ans%=MOD;
            b>>=1,a*=a,a%=MOD;
        }
        //cout<<ans<<endl;
        return ans%MOD;
    }
    
    inline void mul(Matrix a){
        memset(tmp,0,sizeof(tmp));
        for(ll i=1;i<=num+1;i++){
            for(ll j=1;j<=num+1;j++){
                //if(a[j]*b.A[j][i]<0) cout<<a[j]<<" "<<b.A[j][i]<<endl;
                tmp[i]+=res[j]*a.A[j][i];
                if(tmp[i]>=mod) tmp[i]-=mod;
            }
            tmp[i]%=MOD;
        }
        memcpy(res,tmp,sizeof(tmp));
        return;
    }
    
    inline Matrix sq(Matrix a){
        Matrix ans;
        for(ll i=1;i<=num+1;i++)
            for(ll j=1;j<=num+1;j++){
                for(ll k=1;k<=num+1;k++){
                    ans.A[i][j]+=a.A[i][k]*a.A[k][j];
                    if(ans.A[i][j]>=mod) ans.A[i][j]-=mod;
                }
                ans.A[i][j]%=MOD;
            }
        return ans;
    }
    int main(){
        //freopen("1.txt","w",stdout);
        ll T=read(),M=read(),K=read();num=0;
        for(ll i=1;i<=K+1;i++) inv[i]=power(i,MOD-2);
        if(M==1) 
            for(ll i=0;i<=K;i++) 
                sta[i][0][0]=++num; 
        if(M==2) 
            for(ll i=0;i<=K;i++) 
                for(ll j=0;j<=K-i;j++) 
                    sta[i][j][0]=++num;
        if(M==3)
            for(ll i=0;i<=K;i++)
                for(ll j=0;j<=K-i;j++)
                    for(ll k=0;k<=K-i-j;k++)
                        sta[i][j][k]=++num;
        if(M==1){
            for(ll i=0;i<=K;i++){
                ll P=inv[i+1];
                if(i) m[0].A[sta[i][0][0]][sta[i-1][0][0]]=P*i%MOD;
                m[0].A[sta[i][0][0]][sta[i][0][0]]=m[0].A[sta[i][0][0]][num+1]=P;
            }
        }
        if(M==2){
            for(ll i=0;i<=K;i++)
                for(ll j=0;j<=K-i;j++){
                    ll P=inv[i+j+1];
                    if(i) m[0].A[sta[i][j][0]][sta[i-1][j][0]]=P*i%MOD;
                    if(j) m[0].A[sta[i][j][0]][sta[i+1][(i+j<K)?j:j-1][0]]=P*j%MOD;
                    m[0].A[sta[i][j][0]][sta[i][j][0]]=m[0].A[sta[i][j][0]][num+1]=P;
                }
        }
        if(M==3){
            for(ll i=0;i<=K;i++)
                for(ll j=0;j<=K-i;j++)
                    for(ll k=0;k<=K-i-j;k++){
                        ll P=inv[i+j+k+1];
                        if(i) m[0].A[sta[i][j][k]][sta[i-1][j][k]]=P*i%MOD;
                        if(j) m[0].A[sta[i][j][k]][sta[i+1][j-1][(i+j+k<K)?k+1:k]]=P*j%MOD;
                        if(k) m[0].A[sta[i][j][k]][sta[i][j+1][(i+j+k<K)?k:k-1]]=P*k%MOD;
                        m[0].A[sta[i][j][k]][sta[i][j][k]]=m[0].A[sta[i][j][k]][num+1]=P;
                    }
        }
        m[0].A[num+1][num+1]=1;
        for(ll i=1;i<=MAXL;i++) m[i]=sq(m[i-1]);
        while(T--){
            ll N=read(),cnt=0;
            memset(res,0,sizeof(res));
            if(M==1) res[sta[1][0][0]]=1;
            if(M==2) res[sta[0][1][0]]=1;
            if(M==3) res[sta[0][0][1]]=1;
            while(N){
                if(N&1) mul(m[cnt]);
                N>>=1,cnt++;
            }
            printf("%lld
    ",res[num+1]);
        }
        return 0;
    }
  • 相关阅读:
    task-clph
    遍历数组的方式
    iOS事件处理之七种手势
    quatz2d使用注意点
    iOS 细碎知识整理
    九宫格算法图示
    mac10.12的Cocopods安装使用
    静态库冲突的解决办法:duplicate symbol
    ceshi
    xmpp4-总览
  • 原文地址:https://www.cnblogs.com/YSFAC/p/9689899.html
Copyright © 2020-2023  润新知