zoukankan      html  css  js  c++  java
  • 2019.11.9 csp-s 考前模拟

    2019.11.9 csp-s 考前模拟

    是自闭少女lz /lb(泪奔

    T1

    我可能(呸,一定是唯一一个把这个题写炸了的人

    题外话:

    我可能是一个面向数据编程选手

    作为一个唯一一个写炸T1的人,成功通过多组数据将自己的代码改对/(苦笑

    SOLUTION:

    对于某个排列的下一个排列,通过我也不知道是感性还是“李”性李姐,我们可以知道,它一定将当前排列最靠后的一个顺序对变成逆序对

    倒着看就是找最小的一组逆序对

    可以这样理解,从后往前看这个序列,当出现(a_i<a_{i+1})时(由(a_n o a_{i+1})看a的值是递增的),就一定会出现一个逆序对

    然后我们在(a_{i+1} o a_n)中找到最小的(>=a_i)的数,交换它们的位置,然后将(a_{i+1} o a[n])的数按从小到大排序即为答案。

    感性李姐

    以下是鄙人的垃圾归并排序式代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    
    using namespace std;
    
    inline int read() {
    	int ans=0;
    	char last=' ',ch=getchar();
    	while(ch>'9'||ch<'0') last=ch,ch=getchar();
    	while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
    	if(last=='-') ans=-ans;
    	return ans;
    }
    
    int n,a[100010],d[100010];
    int p=214748364,q=-1;
    
    bool msort(int x,int y) {
    	if(x==y) return 0;
    	int mid=(x+y)>>1;
    	bool bj=msort(x,mid);
        //因为要优先在最后选取,又因为倒序储存,所以先递归左区间
    	if(bj) return 1;
    	int i=x,j=mid+1;
    	while(i<=mid&&j<=y) {
    		if((a[i]>a[j]&&q==-1)||(q!=-1&&a[i]>a[q])) {
                //找到了正序中满足a_q<=a_{q+1}的a_q或者找到了更小的>a_q的p
    			p=min(p,i);//找一个下标最小
                //因为a_q之后是有序的所以找下标即可
    			if(q==-1)
    				q=j;//找到a_q以后就不能再次修改q了
    			return 1;
    		} else {
    			i++;
    		}
    	}
    	msort(mid+1,y);
    	return 0;
    }
    
    bool cmp(int a,int b) {
    	return a>b;
    }
    
    int main() {
    	freopen("permutation.in","r",stdin);
    	freopen("permutation.out","w",stdout);
    	n=read();
    	for(int i=n;i>=1;i--) {//倒序储存,从原序列的最后开始查找
    		a[i]=read();
    	}
    	msort(1,n);
    	if(p==214748364&&q==-1) {//是最后一个排列
    		for(int i=1;i<=n;i++)
    			printf("%d ",a[i]);
    		return 0;
    	}
    	swap(a[p],a[q]);
    	sort(a+1,a+q,cmp);
    	for(int i=n;i>=1;i--) 
    		printf("%d ",a[i]);
    	return 0;
    }
    

    然后附上神仙STD:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 1000005
    using namespace std;
    int ai[N];
    bool use[N]={false};
    int main(){
    	freopen("permutation.in","r",stdin);
    	freopen("permutation.out","w",stdout);
    	
    	int n,i,j,t,nt;
    	scanf("%d",&n);
    	for (i=1;i<=n;++i) scanf("%d",&ai[i]);
    	for (i=n;i;--i)
    		if (ai[i]!=n-i+1) break;
    	if (i){
    		for (i=n;i>1;--i){
    			use[ai[i]]=true;
    			if (ai[i-1]<ai[i]){
    				t=ai[i-1];
    				for (j=ai[i-1]+1;j<=n;++j)
    				  	if (use[j]) break;
    				ai[i-1]=j;use[j]=false;
    				use[t]=true;nt=i-1;
    				for (j=1;j<=n;++j)
    					if (use[j]) ai[++nt]=j;
    				break;
    			}
    		}for (i=1;i<=n;++i) printf("%d ",ai[i]);
    		printf("
    ");
    	}else{
    		for (i=1;i<=n;++i) printf("%d ",i);
    		printf("
    ");
    	}
    	
    	fclose(stdin);
    	fclose(stdout);
    }
    

    T2

    SOLUTION

    30pts 暴力搜索:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    
    using namespace std;
    
    inline int read() {
    	int ans=0;
    	char last=' ',ch=getchar();
    	while(ch>'9'||ch<'0') last=ch,ch=getchar();
    	while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
    	if(last=='-') ans=-ans;
    	return ans;
    }
    const int mxn=1010;
    
    int n;
    int xl;
    struct node {
    	int to,nxt;
    }e[mxn<<1];
    int ecnt,head[mxn];
    void add(int from,int to) {
    	++ecnt;
    	e[ecnt].to=to;
    	e[ecnt].nxt=head[from];
    	head[from]=ecnt;
    }
    vector<int> lj[mxn][mxn],Dfs;
    
    int dep[mxn],siz[mxn],yezi;
    int fa[mxn];
    
    void dfs1(int u,int f) {
    	dep[u]=dep[f]+1;
    	siz[u]=1;
    	fa[u]=f;
    	int maxn=-1;
    	for(int i=head[u],v;i;i=e[i].nxt) {
    		v=e[i].to;
    		if(v==f) continue;
    		dfs1(v,u);
    		siz[u]+=siz[v];
    	}
    	if(siz[u]==1) yezi++;
    }
    
    bool vis[mxn];
    void dfs(int u,int from) {
    	for(int i=0;i<Dfs.size();i++) 
    		lj[from][u].push_back(Dfs[i]);
    	for(int i=head[u],v;i;i=e[i].nxt) {
    		v=e[i].to;
    		if(vis[v]) continue;
    		vis[v]=1;
    		Dfs.push_back(v);
    		dfs(v,from);
    		Dfs.pop_back();
    	}
    }
    
    int cnt[mxn][mxn];
    
    int main() {
    	freopen("climb.in","r",stdin);
    	freopen("climb.out","w",stdout);
    	n=read();
    	for(int i=1,u,v;i<n;i++) {
    		u=read();
    		v=read();
    		add(u,v);
    		add(v,u);
    	}
    	dfs1(1,0);
    	for(int i=1;i<=n;i++){
    		memset(vis,0,sizeof(vis));
    		Dfs.push_back(i);
    		vis[i]=1;
    		dfs(i,i);
    		Dfs.pop_back();
    	}
    	int ans[mxn<<5],zz;
    	int nx=1;
    	ans[1]=1;
    	zz=1;
    	bool bj=0;
    	for(int i=1;i<=yezi;i++) {
    		xl=read();
    		for(int j=0,nxx=nx;j<lj[nx][xl].size();j++) {
    			int v=lj[nx][xl][j];
    			if(j!=0) {ans[++zz]=v;
    			cnt[nxx][v]++;
    			cnt[v][nxx]++;
    		}
    			
    			if(cnt[nxx][v]>2||cnt[v][nxx]>2) {
    				bj=1;
    				break;
    			}
    			nxx=v;
    		}
    		nx=xl;
    	}
    	for(int j=0,nxx=1;j<lj[nx][1].size();j++) {
    		int v=lj[nx][1][j];
    		if(j!=0) {ans[++zz]=v;
    		cnt[nxx][v]++;
    		cnt[v][nxx]++;
    	}
    	
    		if(cnt[nxx][v]>2||cnt[v][nxx]>2) {
    			bj=1;
    			break;
    		}
    			nxx=v;
    	}
    	if(bj) printf("-1");
    	else {
    		for(int i=1;i<=zz;i++) 
    			printf("%d ",ans[i]);
    	}
    	return 0;
    }
    

    100 pts:

    考虑给每个叶子赋值,按照题目中给出的遍历顺序,从小到大分别赋值(1 o cnt_{yezi}),记录数组vec[i],表示第i号节点(叶子节点)的遍历顺序(所以好像vec是不满的)对于任意一个节点,维护两个信息:以此节点为根的子树内,vec的最大值和最小值;

    如果对一个点来说:(vec_{max}-vec_{min} e siz_{yezi})(其中(siz_{yezi})表示以点为根的子树中叶子节点的数量),那么就是无解的,输出‘-1’;(也就是最大最小值之差!=叶子节点个数时无解)

    如果有解,如何输出答案?

    首先我们必然是先要遍历题中遍历顺序较早的,那么它对应子树的(vec_{min})也会相应较小,因此我们每次遍历(vec_{min})最小的,顺序输出即可;(对于从小到大遍历(vec)数组,我们可以采用优先队列的方式)

    CODE:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<queue>
    
    using namespace std;
    
    inline int read() {
    	int ans=0;
    	char last=' ',ch=getchar();
    	while(ch>'9'||ch<'0') last=ch,ch=getchar();
    	while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
    	if(last=='-') ans=-ans;
    	return ans;
    }
    const int mxn=101000;
    
    int n;
    int num[mxn],xl;
    struct E {
    	int to,nxt;
    }e[mxn<<1];
    int ecnt,head[mxn];
    void add(int from,int to) {
    	++ecnt;
    	e[ecnt].to=to;
    	e[ecnt].nxt=head[from];
    	head[from]=ecnt;
    }
    struct node {
    	int mx,mn;
    }d[mxn];
    
    int dep[mxn],siz[mxn],yezi;
    int fa[mxn],Siz[mxn];
    bool isye[mxn];
    
    void dfs(int u,int f) {
    	//printf("%d %d
    ",u,f);
    	Siz[u]=1;
    	for(int i=head[u],v;i;i=e[i].nxt) {
    		v=e[i].to;
    		if(v==f) continue;
    		dfs(v,u);
    		Siz[u]+=Siz[v];
    	}
    	if(Siz[u]==1) yezi++;
    }
    bool bj;
    void dfs1(int u,int f) {
    	dep[u]=dep[f]+1;
    	fa[u]=f;
    	if(bj==1) return;
    	d[u].mn=yezi+10;
    	for(int i=head[u],v;i;i=e[i].nxt) {
    		v=e[i].to;
    		if(v==f) continue;
    		dfs1(v,u);
    		siz[u]+=siz[v];
    		d[u].mn=min(d[u].mn,d[v].mn);
    		d[u].mx=max(d[u].mx,d[v].mx);
    	}
    	
    	if(Siz[u]==1) {
    		siz[u]=1;
    		d[u].mn=d[u].mx=num[u];
    		isye[u]=1;
    	}
    	if(d[u].mx-d[u].mn+1!=siz[u]) bj=1;
    	return ;
    }
    
    struct Node{
    	int ll,ord;
    }hed;
    
    inline bool operator < (const Node &a,const Node &b)
    {
    	return a.ll>b.ll;
    }
    
    void dfs2(int u) {
    	printf("%d ",u);
    	if(isye[u]) 
    		return;
    	priority_queue<Node> q;
    	for(int i=head[u],v;i;i=e[i].nxt) {
    		v=e[i].to;
    		if(v==fa[u]) continue;
    		q.push(Node{d[v].mn,v});
    	}
    	while(!q.empty()) {
    		Node p=q.top();
    		q.pop();
    		dfs2(p.ord);
    		printf("%d ",u);
    	}
    }
    
    int main() {
    	freopen("climb.in","r",stdin);
    	freopen("climb.out","w",stdout);
    	n=read();
    	for(int i=1,u,v;i<n;i++) {
    		u=read();
    		v=read();
    		add(u,v);
    		add(v,u);
    	}
    	dfs(1,0);
    	for(int i=1;i<=yezi;i++) {
    		xl=read();
    		num[xl]=i;
    	}
    	dfs1(1,0);
    	if(bj==1) printf("-1");
    	else {
    		dfs2(1);
    	}
    	return 0;
    }
    

    T3:

    SOLUTION:

    对于这道题的solution迷迷糊糊懵懵懂懂说不上不懂,也说不上懂(wtnl

    所以我要复制solution了xk(笑哭

    ~~题解乱码了* ~~

    首先我们要先对两个数组排序

    然后通过预处理处理出数组p[i]表示b[x]<a[i]的b的极大个数(讲简单一点就是有多少个b[x]是小于a[i]的

    (f[i][k])表示对于前i个派,至少有k组a[i]>b[j]的方案;

    为什么是至少呢?因为在这里我们只是枚举A前i个位置,B的所有位置,并且满足A>B的k个A分配了B,剩余的A与B是没有配对的,而这些人机之间会不会又产生新的配对,我们是没有办法确定的,但我们确认已经有k对了,因此是至少。

    那么对于(f[i][k]=f[i-1][k]+f[i-1][k-1] imes(p[i]-(k-1)))

    如何理解?

    (f[i-1][k])表示的是前i-1个派至少有k对(a_p>b_q),此时我们不给(a_i)配对

    (f[i-1][k-1])表示的是前i-1个派至少有k-1对(a_p>b_q),这个时候我们需要给(a_i)配对,那么可以让(a_i)和谁配对呢?显然我们刚刚预处理的p数组就有用了,显然因为序列都是递增的,因此前k-1个(a_k)的配对也一定在p[i]数组所包含的范围内,所以除去那k-1个已经与前k-1个(a_k)配对的(b_l),还有剩余(p[i]-(k-1))(b_l)可供选择,那么(a_i)的配对方案就有(p[i]-(k-1))个。

    然后这显然不是最后的答案

    我们设g[i]表示前n个派,恰好有i组a[x]>b[x];

    容斥一下:

    (g[i]=f[n][i]*(n-i)!-g[j] imes C_j^i)

    感性理解:

    (f[n][i])分配了i个A,剩余的A与B有(A_{n-i}^{n-i} 即 (n-i)!)种可能的搭配,然后容斥减掉(g[j] imes C_j^i jin[i+1,n])

    最后答案是g[s];

    s-(n-s)=k;

    得s=(n+k)/2;

    n+k为奇数时答案为0;

    //放弃挣扎,瞧着可读性极低的std:
    #include<iostream>
    #include<cstdio>
    #include<algorithm> 
    #define N 2010
    #define P 1000000009 
    
    using namespace std;
    
    int i,j,a[N],b[N],s[N],n,k,t,p;
    long long f[N][N],g[N],c[N][N],fa[N];
    
    int main() {
    	freopen("pie.in","r",stdin);
    	freopen("pie.out","w",stdout); 
    	scanf("%d%d",&n,&k);
    	t=(n+k)/2;
    	if ((n+k)%2) {
    		cout<<0<<endl;
    		return 0;
    	}
    	for (i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	for (i=1;i<=n;i++)
    		scanf("%d",&b[i]);
    	sort(a+1,a+n+1);
    	sort(b+1,b+n+1);
    	for (i=1,p=1;i<=n;i++) {
    		while(p<=n&&b[p]<a[i])
    			p++;
    		s[i]=p-1;
    	}
    	for(i=0;i<=n;i++) {
    		c[i][0]=1;
    		for(j=1;j<=i;j++) 
    			c[i][j]=(c[i-1][j]+c[i-1][j-1])%P;
    	}
    	for(fa[0]=1,i=1;i<=n;i++)
    		fa[i]=fa[i-1]*i%P;  
    	for(f[0][0]=f[1][0]=1,i=1;i<=n;i++,f[i][0]=1)
    		for(j=1;j<=i;j++)f[i][j]=(f[i-1][j]+f[i-1][j-1]*max(s[i]-(j-1),0))%P;
    	for(i=n;i>=t;i--){  
    		g[i]=f[n][i]*fa[n-i]%P;  
    		for(j=i+1;j<=n;j++)
    			(g[i]+=P-g[j]*c[j][i]%P)%=P;//g[i]=(g[i]-(g[j]*c[j][i]%P)+P)%P  
    	}  
    	cout<<g[t]<<endl;
    	return 0;
    }
    
  • 相关阅读:
    注册机实现算法
    nginx优化配置服务,快速提升服务器性能,突破100000万高并发不是梦!
    语雀、有道云笔记、滴答清单一键保存文章,剪藏文章chrom、360极速浏览器火狐插件
    超简单!查询自己在CSDN、博客园、简书、知乎、51CTO等平台的百度收录情况
    最全的中文Vscode扩展插件&配置调试&快捷键&格式化方法
    中文汉化atom最美前端开发编辑器插件安装和常用配置&快捷键,5年的使用心得
    加速Github访问,最新地址仅需1步!修改host快速达到2M!
    使用标签link rel="alternate"属性,帮助搜索引擎对不同设备的用户提供不同类型的页面
    JavaScript高级程序设计学习笔记(1)
    idea中多模块项目引入
  • 原文地址:https://www.cnblogs.com/zhuier-xquan/p/11829046.html
Copyright © 2011-2022 走看看