ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「NOIP2021模拟赛8.23 C」棒棒糖女孩(lollipop)题解

2021-08-24 10:04:09  阅读:171  来源: 互联网

标签:15 int 题解 pos len ++ DFS 8.23 NOIP2021


题目大意

「NOIP2021模拟赛8.23 C」棒棒糖女孩(lollipop)

有一个\(1∼n\)的排列,其中有\(m\)个位置上的数缺失了。

已知这个排列的逆序对数恰好为\(k\),求有多少种可能的排列。

问题解决

我们发现\(m\)很小,也就是说可以暴力枚举\(m\)个数的顺序,但是发现时间复杂度是\(O(m!)\)还是太大,考虑折半搜索,先枚举组合数讲\(m\)个数分成两堆,一半在前面,一半在后面,然后其中他们之间的代价就可以算好了,之后再枚举全排列,将他们之间的代价算好,最后用一个桶记录一下逆序对数,将两边的方案结合一下就好了,注意统计答案的时候要预处理出一些东西,方便与\(O(1)\)来更新答案

代码实现

#pragma GCC optimize(2)
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=200005;
int N,a[maxn],pre_max[maxn][15],lst_min[maxn][15],M,b[15],c[maxn],A[15],B[15],len_B,len_A,A_[15],B_[15],G[1<<8][8],bob[maxn<<3],p,stack[maxn],top,sum;
int ans,K;
LL Ans;
int vis[maxn],vis_1[15];
inline int read(){
	int ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}
void add_x(int x,int data){for(int i=x;i<=N;i+=i&-i)c[i]+=data;}
int get(int x){int ret=0;for(int i=x;i;i-=i&-i)ret+=c[i];return ret;}
void DFS_1(int x,int s,int k){
	if(x==len_A+1){
		bob[k]++;stack[++top]=k;
	}
	if(A[1]==2)
		vis_1[1]=0;
	for(int i=1;i<=len_A;i++)if(!(s>>(i-1)&1)){
		A_[x]=A[i];DFS_1(x+1,s|(1<<(i-1)),k+G[s|(1<<(i-1))][i]+pre_max[A[i]][x]+lst_min[A[i]][x]);A_[x]=0;
	}
}
void DFS_2(int x,int s,int k){
	if(x==len_B+1){
		ans+=(bob[K-p-k-sum]);
	}
	for(int i=1;i<=len_B;i++)if(!(s>>(i-1)&1)){
		B_[x]=B[i];DFS_2(x+1,s|(1<<(i-1)),k+G[(s|(1<<i-1))][i]+pre_max[B[i]][x+len_A]+lst_min[B[i]][x+len_A]);B_[x]=0;
	}
}
void check(){
	for(int i=1;i<=top;i++)bob[stack[i]]=0;top=0;
	sort(A+1,A+1+len_A);
	DFS_1(1,0,0);
	sort(B+1,B+1+len_B);
	p=0;for(int i=1;i<=len_A;i++)for(int j=1;j<=len_B;j++)(A[i]>B[j])&&(p++,0);
	ans=0;
	DFS_2(1,0,0);
	Ans+=ans;
}
void DFS(int pos){
	if(pos==(M)+1){
		check();return ;
	}
	if(len_A<(M>>1)){A[++len_A]=b[pos];DFS(pos+1);A[len_A--]=0;}
	if(len_B<(M-(M>>1))){B[++len_B]=b[pos];DFS(pos+1);B[len_B--]=0;}
}
int main(){
	freopen("lollipop.in","r",stdin);
	freopen("lollipop.out","w",stdout);
	N=read();K=read();
	for(int i=1;i<=N;i++)a[i]=read(),vis[a[i]]=1;
	for(int i=N;i;i--)if(a[i]){sum+=get(a[i]);add_x(a[i],1);}
	for(int i=1;i<=N;i++)(!vis[i])&&(b[++M]=i,0);
	for(int i=1;i<=M;i++){int num=0,p=0;for(int j=1;j<=N;j++){(a[j]>b[i])&&(num++,0);(!a[j])&&(pre_max[b[i]][++p]=num,0);}}
	for(int i=1;i<=M;i++){int num=0,p=M;for(int j=N;j;j--){(a[j]<b[i]&&a[j]>0)&&(num++,0);(!a[j])&&(lst_min[b[i]][p--]=num,0);}}
	for(int i=0;i<(1<<(M+1>>1));i++)
		for(int j=1;j<=(M+1>>1);j++)if((i>>j-1)&1){
			for(int k=j+1;k<=(M+1>>1);k++){
				G[i][j]+=(i>>k-1)&1;
			}
		}
	DFS(1);
	printf("%lld\n",Ans);
	return 0;
}

标签:15,int,题解,pos,len,++,DFS,8.23,NOIP2021
来源: https://www.cnblogs.com/martian148/p/15178930.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有