zoukankan      html  css  js  c++  java
  • [NowCoder]牛客OI周赛3

    A.地斗主

    题意:\(4\times N\) 的地板,在上面铺 \(1\times 2\)\(2\times 1\) 的地砖,求铺满方案数, \(N\le 10^9\)

    原题。。先把一列的状态压缩成二进制,这一格为1就表示这一格被左边一列横着占用了

    为0表示没被左边占用(放了竖着的或者没放都是一样的)

    可以推出一系列转移,最后发现有用状态只有6个,有两个方案数总是一样,可以合并

    因此用矩阵乘法加速递推即可

    #include<bits/stdc++.h>
    #define REP(i,a,b) for(int i(a);i<=(b);++i)
    using namespace std;
    typedef long long ll;
    inline int read(){char c,p=0;int w;
    	while(isspace(c=getchar()));if(c=='-')p=1,c=getchar();
    	for(w=c&15;isdigit(c=getchar());w=w*10+(c&15));return p?-w:w;
    }
    int n,m;
    struct mat{
    	int v[5][5];
    	mat(){memset(v,0,sizeof v);}
    	inline int*operator[](const int&i){return v[i];}
    	inline mat operator*(mat&r){
    		mat ans;REP(k,0,4)REP(i,0,4)REP(j,0,4)
    		ans[i][j]=(ans[i][j]+1ll*v[i][k]*r[k][j])%m;
    		return ans;
    	}
    }A,B,C;
    inline mat fpow(mat x,int k){
    	mat r;REP(i,0,4)r[i][i]=1;
    	for(;k;k>>=1,x=x*x)if(k&1)r=r*x;return r;
    }
    int main(){
    	A[0][0]=A[0][1]=A[0][4]=1;A[0][2]=2;
    	A[1][0]=A[2][0]=1,A[2][2]=1,A[3][4]=1,
    	A[4][0]=A[4][3]=1;
    	B[0][0]=1;
    	int T=read();
    	while(T--){
    		n=read(),m=read();
    		C=fpow(A,n)*B;
    		io.print(C[0][0]);
    	}
    	return 0;
    }
    

    B.1048

    题意:\(N\) 个白球和 \(N\) 个黑球,每个都以 \(1\dots N\) 标号,现在给出每个球的颜色和标号,要求用最少的步数邻项交换,使得白球是有序的,黑球也是有序的,\(N\le 2000\)

    由邻项交换可以想到冒泡排序,冒泡排序的最小交换次数是逆序对,考虑DP

    \(f[i][j]\) 表示 已经排了前 \(i\) 个白球,前 \(j\) 个黑球(都在最前面)的最小代价。

    若用 \(i\) 转移,则代价是 在 \(i\) 前面,比 \(i\) 大的白球数目 和 在 \(i\) 前面, 比 \(j\) 大的黑球数目,简单起见用 \(c1[i]\) 表示;同理,若用 \(j\) 转移,代价是 \(c2[j]\)

    \[f[i][j]=min(f[i-1][j]+c1[i],f[i][j-1]+c2[j]) \]

    #include<bits/stdc++.h>
    #define REP(i,a,b) for(int i(a);i<=(b);++i)
    #define dbg(...) fprintf(stderr,__VA_ARGS__)
    using namespace std;
    template<typename T,typename U>inline char smin(T&x,const U&y){return x>y?x=y,1:0;}
    template<typename T,typename U>inline char smax(T&x,const U&y){return x<y?x=y,1:0;}
    const int N=2005;
    int n,f[N][N],p[2][N],cnt[2][N<<1][N];
    int main(){
    	scanf("%d",&n);
    	REP(i,1,n<<1){
    		char c;int x;scanf("%s%d",&c,&x);
    		p[c=='B'][x]=i;
    		REP(j,i,n<<1)++cnt[c=='B'][j][x];
    	}
    	REP(k,0,1)REP(i,1,n<<1)for(int j=n;~j;--j)cnt[k][i][j]+=cnt[k][i][j+1];
    	REP(i,0,n)REP(j,0,n){
    		if(i||j)f[i][j]=1e9;
    		if(i)smin(f[i][j],f[i-1][j]+cnt[1][p[0][i]-1][j+1]+cnt[0][p[0][i]-1][i+1]);
    		if(j)smin(f[i][j],f[i][j-1]+cnt[0][p[1][j]-1][i+1]+cnt[1][p[1][j]-1][j+1]);
    	}
    	cout<<f[n][n];
    	return 0;
    }
    
    
    

    C.爆瓶子

    题意:你有 \(N\) 种瓶子每种 \(N\) 个,需要把它排成 \(N\times N\) 的方阵,要求每行每列不能有相同瓶子,输出字典序最小的方案 \(N \le 220\)

    垃圾题,跟着数据卡数据范围,暴力二分图匹配

    一行一行进行二分图匹配,匹配了就把对应的边删掉,得出一组匹配后再看能不能和前面交换得到字典序更小的匹配

    #include<bits/stdc++.h>
    #define REP(i,a,b) for(int i(a);i<=(b);++i)
    using namespace std;
    inline int read(){char c,p=0;int w;
    	while(isspace(c=getchar()));if(c=='-')p=1,c=getchar();
    	for(w=c&15;isdigit(c=getchar());w=w*10+(c&15));return p?-w:w;
    }
    const int N=225;
    int n,m,head[N],pre[N][N],nxt[N][N],vis[N],T,bel[N],to[N];
    inline void del(int i,int j){
    	if(j==head[i])head[i]=nxt[i][j];
    	else pre[i][nxt[i][j]]=pre[i][j],nxt[i][pre[i][j]]=nxt[i][j];
    }
    inline bool dfs(int x,int lim){
    	for(int i=head[x];i;i=nxt[x][i])if(vis[i]!=T){
    		vis[i]=T;
    		if(!bel[i]||bel[i]>lim&&dfs(bel[i],lim))
    		return to[x]=i,bel[i]=x,1;
    	}
    	return 0;
    }
    inline void solve(){
    	REP(i,1,n)++T,dfs(i,0);
    	REP(i,1,n){
    		++T;
    		for(int j=head[i];j;j=nxt[i][j]){
    			if(bel[j]==i)break;
    			if(bel[j]<i)continue;
    			int x=bel[j],y=to[i];
    			to[i]=j,bel[j]=i,to[x]=bel[y]=0;
    			if(dfs(x,i))break;
    			to[x]=j,bel[j]=x,to[i]=y,bel[y]=i;
    		}
    	}
    }
    int main(){
    	int t=read();
    	while(t--){
    		n=read();m=read();
    		REP(i,1,n){
    			REP(j,1,n)pre[i][j]=j-1,nxt[i][j]=j+1;nxt[i][n]=0;head[i]=1;
    		}
    		REP(i,1,m)REP(j,1,n)del(j,read());
    		REP(i,m+1,n){
    			memset(to,0,sizeof to);
    			memset(bel,0,sizeof bel);
    			memset(vis,0,sizeof vis);
    			T=0,solve();
    			REP(j,1,n)del(j,to[j]),printf("%d ",to[j]);puts("");
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    python多线程
    python网络编程-udp/tcp通信
    通达OA未授权任意文件上传及文件包含导致远程代码执行漏洞
    星盟安全awd复盘20200314
    Axublog1.1.0代码审计
    回调函数绕过D盾小套路
    php7.1后webshell免杀的去路
    GO语言 特性概要
    Openstack 笔记概要
    大数据--基本理论知识(1)
  • 原文地址:https://www.cnblogs.com/HolyK/p/9835130.html
Copyright © 2011-2022 走看看