2018.9.11离线赛 by Isrothy

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Caristra/article/details/82691015

T1——jsr(3910)

Description:

给你一个初始数字 A ,和目标数字 B .你需要按照以下操作将 A 变为 B .
数字 x 的二进制式(可以有前导 0 )下,将 0 , 1 的位置任意排列.再令 x + 1 .
求最少次数的操作将 A 变为 B .若无解,输出 1 .
A , B 10 18

Solution:

  • 初看此题,感觉是道与dp或bfs的题.
  • 但模拟小数据及特殊点的数据,发现了一些规律.
  • 因为操作中最后必须 + 1 ,那么 A 就必须先变为 ( B 1 ) ,
  • 再回溯一下,就是 A 要变为二进制下 1 的个数与 ( B 1 ) 的二进制下 1 的个数相同.
  • 那么就想到分类讨论一下.二进制下,A的1的个数与(B-1)的1的个数的大小.
  • 再模拟验证一下就不难解出了.
  • 注意:builtinpopcount()只能适用于int,而要在long long 下适用,就在函数名后加’ll’.

Code:

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize("Ofast")
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;

template<class T>inline void Rd(T &x){
    x=0;char c;
    while((c=getchar())<48);
    do x=(x<<1)+(x<<3)+(c^48);
    while((c=getchar())>47);
}

ll a,b;

int main(){
//  freopen("jsr.in","r",stdin);
//  freopen("jsr.out","w",stdout);
    int cas;cin>>cas;
    while(cas--){
        Rd(a),Rd(b); 
        if(a==b){puts("0");continue;}
        else if(!b && a || b==1 && a>1){puts("-1");continue;}
        int cnta=__builtin_popcountll(a),cntb=__builtin_popcountll(b-1);
        if(cntb>=cnta)printf("%d\n",cntb-cnta+1);
        else puts("2");
    }
    return 0;
}

T2——mianma(3911)

Description:

n m 的矩形中,每个格子都有颜色 A i , j ,求颜色种类小于等于 2 的最大的联通块大小.
n , m 1000 , A i , j n m

Solution:

  • 对于颜色种类为 2 的联通块.看似无从下手.
  • 实则还是比较常规的操作.
  • 处理每个颜色的联通块,再建图.
  • 这里,可以用并查集先将同一个颜色的联通块并其起来,在考虑不同颜色的.
  • 再考虑不同颜色的时候,我们还是枚举当前颜色的联通块连向的其它的颜色的联通块.
  • 然后在用并查集合并,再回溯.
  • 但这样枚举的复杂度为 Θ ( n 2 m 2 ) .显然是不行的.
  • 但是呢,我们发现这些边最多只有 n m 条.
  • 所以我们先将颜色排序,做到当前的颜色连向的其它的联通块的颜色是堆在一起的.
  • 那么我们就将联通块的id(基数)计数排序即可.
  • 这样,就可以做到 Θ ( n m α ( n m ) )

Code:

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize("Ofast")
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;

//inline char Sc(){
//  static const int LEN=100000;
//  static char Buf[LEN],*OP=Buf,*ED=Buf;
//  if (OP==ED) ED=(OP=Buf)+fread(Buf,1,LEN,stdin);
//  return *OP++;
//}
//template<class T>inline void Rd(T &x){
//  static char c;
//  for (x=0,c=Sc();c<48;c=Sc());
//  for (;c>47;c=Sc()) x=(x<<1)+(x<<3)+(c^48);
//}

template<class T>inline void Rd(T &x){
    x=0;char c;
    while((c=getchar())<48);
    do x=(x<<1)+(x<<3)+(c^48);
    while((c=getchar())>47);
}

#define N 1002

int p,cas;
int n,m;
int A[N][N];

const int dx[]={-1,0,1,0};
const int dy[]={0,1,0,-1};
bool check(int x,int y){return x<1 || x>n || y<1 || y>m;}

struct p50{

    int id1,id2;
    int sum;

    bool vis[502][502];

    void dfs(int x,int y){
        if(A[x][y]!=id1 && A[x][y]!=id2 || vis[x][y])return;
        ++sum;
        vis[x][y]=1;
        SREP(i,0,4){
            int nx=x+dx[i],ny=y+dy[i];
            if(check(nx,ny))continue;
            dfs(nx,ny); 
        }
    }

    void solve(){
        while(cas--){

            Rd(n),Rd(m);

            int mxc=0;
            REP(i,1,n) REP(j,1,m) Rd(A[i][j]),chkmax(mxc,A[i][j]); 
            int ans=0;
            REP(i,1,mxc) REP(j,1,mxc){
                id1=i,id2=j;
                mcl(vis,0);
                REP(x,1,n) REP(y,1,m){
                    if(vis[x][y])continue;
                    sum=0;
                    dfs(x,y);
                    chkmax(ans,sum);
                }
            }

            printf("%d\n",ans);

        }
    }
}p1;

struct p20{

    int id1,id2;

    void solve(){
        while(cas--){
            Rd(n),Rd(m);
            REP(i,1,n) REP(j,1,m) Rd(A[i][j]);
            int ans=0;
            REP(i,1,m){
                id1=A[1][i],id2=0;
                REP(j,i,m){
                    if(A[1][j]!=id1 && !id2)id2=A[1][j];
                    else if(A[1][j]!=id1 && A[1][j]!=id2){chkmax(ans,j-i);break;}
                }
            }

            printf("%d\n",ans);
        }
    }
}p2;

struct p10{
    #define S 502
    int Id[S][S],tot;
    int sz[S*S],col[S*S];
    vector<int>E[S*S];
    map<int,bool>mp[S*S];
    bool vis[S*S];

    int ans;

    void dfs1(int x,int y){
        Id[x][y]=tot;
        ++sz[tot];
        SREP(i,0,4){
            int nx=x+dx[i],ny=y+dy[i];
            if(check(nx,ny))continue;
            if(A[nx][ny]!=A[x][y] || Id[x][y])continue;
            dfs1(nx,ny);
        }
    }

    void dfs2(int x,int col1,int col2,int sum){
        chkmax(ans,sum);
        SREP(i,0,E[x].size()){
            int y=E[x][i];
            if(vis[y])continue;
            if(col1==col[y]){
                vis[y]=1;
                dfs2(y,col1,col2,sum+sz[y]);
                vis[y]=0;
            }
            else if(!col2 || col2==col[y]){
                vis[y]=1;
                dfs2(y,col1,col[y],sum+sz[y]);
                vis[y]=0;
            }
        }
    }

    void Clear(){
        ans=0;
        tot=0;
        mcl(Id,0);
        mcl(sz,0);
        REP(i,1,n*m)E[i].clear(),mp[i].clear();
    }

    void solve(){

        while(cas--){

            Rd(n),Rd(m);

            Clear();

            REP(i,1,n) REP(j,1,m) Rd(A[i][j]);

            REP(i,1,n) REP(j,1,m) {
                if(Id[i][j])continue;
                tot++;
                col[tot]=A[i][j];
                dfs1(i,j);
            }

            REP(x,1,n) REP(y,1,m) SREP(d,0,4){
                int nx=x+dx[d],ny=y+dy[d];
                if(check(nx,ny))continue;
                int id1=Id[x][y],id2=Id[nx][ny];
                if(id1==id2)continue;
                if(mp[id1][id2])continue;
                mp[id1][id2]=mp[id2][id1]=1;
                E[id1].pb(id2);
                E[id2].pb(id1);
            }

            REP(i,1,tot){
                vis[i]=1;
                dfs2(i,col[i],0,sz[i]);
                vis[i]=0;
            }

            printf("%d\n",ans);

        }
    }
}p3;

struct p100{

    int col[N*N],sz[N*N],fa[N*N],Id[N*N];
    int stk[N*N<<2],top;

    int qwq,head[N*N];
    struct edge{
        int from,to,nxt;
    }E[N*N<<2];
    void addedge(int x,int y){E[qwq]=(edge){x,y,head[col[x]]};head[col[x]]=qwq++;}
    int tmp[N*N];

    int ans;

    int getid(int x,int y){return (x-1)*m+y;}

    int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}

    bool merge(int a,int b){
        a=find(a),b=find(b);
        if(a==b)return 0;
        sz[a]+=sz[b];
        fa[b]=a;
        chkmax(ans,sz[a]);
        return 1;
    }

    int cnt[N*N];

    void Sort(){
        mcl(cnt,0);
        REP(i,1,n*m) ++cnt[col[Id[i]]&1023];
        REP(i,1,1024) cnt[i]+=cnt[i-1];
        DREP(i,n*m,0) tmp[cnt[col[Id[i]]&1023]--]=Id[i];
        mcl(cnt,0);
        REP(i,1,n*m) ++cnt[col[tmp[i]]>>10];
        REP(i,1,1024) cnt[i]+=cnt[i-1];
        DREP(i,n*m,0) Id[cnt[col[tmp[i]]>>10]--]=tmp[i];
    }

    void Clear(){

        qwq=0;
        mcl(head,-1); 

        REP(i,1,n*m)fa[i]=Id[i]=i,sz[i]=1;
        ans=0;
    }

    void solve(){
        while(cas--){
            Rd(n),Rd(m);

            Clear();

            REP(i,1,n){
                REP(j,1,m){
                    Rd(A[i][j]);
                    col[getid(i,j)]=A[i][j];
                    REP(k,0,1){
                        int lx=i-k,ly=j-(k^1);
                        if(check(lx,ly))continue;
                        if(A[lx][ly]==A[i][j]) merge(getid(i,j),getid(lx,ly));
                    }
                }
            }

            Sort();

            REP(i,1,n*m) {
                int x=(Id[i]-1)/m+1,y=(Id[i]-1)%m+1;
                SREP(k,0,4){
                    int nx=x+dx[k],ny=y+dy[k];
                    if(check(nx,ny))continue;
                    if(A[x][y]<A[nx][ny])addedge(find(getid(nx,ny)),find(Id[i]));
                }
            }

            mcp(tmp,sz);

            REP(x,1,n*m) for(int i=head[x],j=i;~i;i=j){
                int c=col[E[i].to];
                while(~j && c==col[E[j].to]){
                    if(merge(E[j].to,E[j].from)){
                        stk[++top]=E[j].to;
                        stk[++top]=E[j].from;
                    }
                    j=E[j].nxt;
                }
                REP(j,1,top)sz[stk[j]]=tmp[stk[j]],fa[stk[j]]=stk[j];
                top=0;
            }

            printf("%d\n",ans);
        }
    }
}p4;

int main(){
//  freopen("mianma.in","r",stdin);
//  freopen("mianma.out","w",stdout);

    Rd(p),Rd(cas);

    if(p<=10)p1.solve();
    else if(p>=13 && p<=16)p2.solve();
    else if(p<=12)p3.solve();
    else p4.solve();

    return 0;
}

T3——rust(3912)

Description:

在一个周长为 h 的圆上,有 n X Z H 排列在圆上,为了捕捉 X Z H , I s r o t h y 有一个长度为 x 的捕捉器,那么捕捉器可以捕捉到在起点为 s 到终点为 s + x 1 X Z H ,但圆上每个点做为起点都有一个概率的权值 A i .求捕捉到的 X Z H 的个数的期望.
由于出题人强行加强了难度.只告诉你 [ 1 , m ] A i C i .
只能通过 A i = j m A i j C j 计算出 [ m , h ] A i .
n 3000 , h 10 9 , m 100

Solution:

扫描二维码关注公众号,回复: 3450108 查看本文章
  • 不难分析,本题的难点就是这个 h 非常大,所以我们无法去直接计算的.
  • 但进行模拟几个 A i 后,发现这其实是在求常系数齐次线性递推数列的某一项.
  • 这不就是矩阵乘法的经典模型了吗…
  • 再回忆一下矩阵乘法. P 1 × i = 1 k P 2 2 k
  • P 2 2 k 是可以在 Θ ( m 3 log h ) 的时间复杂度内预处理出来的.
  • 再来看 P 1 矩阵,可以发现, P 1 矩阵实际上只有一列是有元素的.
  • 于是,一次矩阵乘法的复杂度就优化成了 Θ ( m 2 ) .
  • 总时间复杂度是 Θ ( m 3 log h + n m 2 log h ) .

Code:

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize("Ofast")
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;

template<class T>inline void Rd(T &x){
    x=0;char c;
    while((c=getchar())<48);
    do x=(x<<1)+(x<<3)+(c^48);
    while((c=getchar())>47);
}

#define N 3002
#define M 32002
#define MM 2000002
#define mod 998244353

int n,m,h,x;
int p[N];
int A[MM],C[N];

void Add(int &x,int y){
    x+=y;
    if(x>=mod)x-=mod;
    else if(x<0)x+=mod;
}

int Pow(int a,int b){
    int x=1;
    while(b){
        if(b&1)x=1ll*x*a%mod;
        a=1ll*a*a%mod,b>>=1;
    }
    return x;
}

struct p36{

    int cnt[MM];

    void solve(){
        REP(i,m+1,h) REP(j,1,m) Add(A[i],1ll*A[i-j]*C[j]%mod);

        int sum=0;
        REP(i,1,h){
            A[i+h]=A[i];
            Add(sum,A[i]);
        }

        REP(i,1,n)++cnt[p[i]],++cnt[p[i]+h];
        REP(i,1,h+x+1)Add(cnt[i],cnt[i-1]);

        int ans=0;
        REP(i,1,h)Add(ans,1ll*A[i]*(cnt[i+x-1]-cnt[i-1])%mod);

        printf("%d\n",1ll*ans*Pow(sum,mod-2)%mod);

    }
}p1;

struct Matrix{
    int a[102][102];
    Matrix(){mcl(a,0);}
    Matrix operator*(const Matrix &B)const{
        Matrix res;
        REP(i,1,m+1) REP(j,1,m+1) REP(k,1,m+1) Add(res.a[i][j],1ll*a[i][k]*B.a[k][j]%mod);
        return res;
    }
}Ans,Res[34],P1,P2;

Matrix Mul(Matrix a,Matrix b){
    Matrix res;
    REP(j,1,m+1) REP(k,1,m+1) Add(res.a[1][j],1ll*a.a[1][k]*b.a[k][j]%mod);
    return res;
}

struct p72{

    void Init(){
        int tmp=0;
        REP(i,1,m){
            if(i<m)Add(tmp,A[i]);
            P1.a[1][i]=A[m-i+1];
        }
        P1.a[1][m+1]=tmp;
        REP(i,1,m)P2.a[i][1]=C[i];
        REP(i,2,m)P2.a[i-1][i]=1;
        P2.a[1][m+1]=1;
        P2.a[m+1][m+1]=1;
        Ans=P1;
        Res[0]=P2;
        REP(i,1,31)Res[i]=Res[i-1]*Res[i-1];
    }

    void calc(int k){
        int cnt=0;
        while(k){
            if(k&1)Ans=Mul(Ans,Res[cnt]);
            cnt++;
            k>>=1;
        }
    }

    void solve(){

        Init();
        sort(p+1,p+1+n);

        int ans=0;
        REP(i,1,n){
            if(p[i]<=m)Add(ans,A[p[i]]);
            else {
                calc(p[i]-(p[i-1]<m?m:p[i-1]));
                Add(ans,Ans.a[1][1]);
            }
        }
        calc(h-(p[n]<m?m:p[n]));

        int sum=(Ans.a[1][1]+Ans.a[1][m+1])%mod;
        printf("%d\n",1ll*ans*Pow(sum,mod-2)%mod);

    }
}p2;


struct p100{

    int tmp[M];

    void Init(){
        REP(i,1,m){
            Add(tmp[i]=tmp[i-1],A[i]);
            P1.a[1][i]=A[m-i+1];    
        }
        P1.a[1][m+1]=tmp[m-1];
        REP(i,1,m)P2.a[i][1]=C[i];
        REP(i,2,m)P2.a[i-1][i]=1;
        P2.a[1][m+1]=P2.a[m+1][m+1]=1;
        Res[0]=P2;
        REP(i,1,31)Res[i]=Res[i-1]*Res[i-1];
    }

    void calc(int k){
        int cnt=0;
        while(k){
            if(k&1)Ans=Mul(Ans,Res[cnt]);
            k>>=1;
            cnt++; 
        }
    }

    int Get(int x){
        if(x<=m)return tmp[x];
        Ans=P1;
        calc(x-m);
        return (Ans.a[1][1]+Ans.a[1][m+1])%mod;
    }

    int Sum(int l,int r){
        return (Get(r)-Get(l-1)+mod)%mod;
    }

    void solve(){

        Init();

        int ans=0;

        REP(i,1,n){
            int L=p[i]-x+1,R=p[i];
            if(L>=1)Add(ans,Sum(L,R));
            else{
                Add(ans,Sum(1,R));
                Add(ans,Sum(L+h,h));
            } 
        }

        Ans=P1;
        calc(h-m);

        int sum=(Ans.a[1][1]+Ans.a[1][m+1])%mod;
        printf("%d\n",1ll*ans*Pow(sum,mod-2)%mod);
    }
}p3;

int main(){
//  freopen("rust.in","r",stdin);
//  freopen("rust.out","w",stdout);

    scanf("%d%d%d%d",&n,&h,&x,&m);
    REP(i,1,n)scanf("%d",&p[i]);
    REP(i,1,m)scanf("%d",&A[i]);
    REP(i,1,m)scanf("%d",&C[i]);

    if(h<=1e6)p1.solve();
    else if(x==1)p2.solve();
    else p3.solve();

    return 0;
}

Summary:

  • 感觉今天 I s r o t h y 的题都是 M e d i u m a n d H a r d 的题…以及 T 3 还魔改成 N T T .
  • 但基础分都是比较足的,以及好拿的分也有挺多的…导致大家分数很紧凑
  • 但由于自己的无知,用了builtin_popcount,怒少40…
  • 还有就是 T 2 的联通块感觉自己还是比较陌生,没有一点这方面的套路.
  • 最后 T 3 的矩阵乘法用的还是不够熟练,有一档前缀和的没推出来,以及套路的预处理 P o w 不知道.
  • 综上,感觉这套卷子非常有意义,既能找出不足,还能学习一些新知识.但整体卷子的难度偏难.还是蒟蒻太菜了...
  • 评价:较良心出题人.

猜你喜欢

转载自blog.csdn.net/Caristra/article/details/82691015