版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/89190059
这道题的加强版
对原搜索的程序基础上,预处理一个 和 ,表示当前状态剩下的数能组成的最大值和最小值,这样就可以除掉很多的枝
本来这样理应过掉我们学校题库的题的了
但是!
由于学校题库太卡了(时限500 ),把队友一直卡到90分,我帮他一直优化,从 优化到了 (优化了位运算,添加了 操作)
还是没
连题解的标都过不了
没办法,最后只好打表过了
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include<cstdio>
#include<cstdlib>
#define lb(x) (x)&(-x)
using namespace std;
const int N=21;
int n,m,a[N],f[N][N],maxn[1<<N],minn[1<<N],log[1<<N];
bool used[N];
inline int count(int x)
{
int cnt=0;while(x){x-=lb(x);cnt++;}
return cnt;
}
inline int summax(int k,int x)
{
int cnt=0,i=n,j=k,y=0;
while(x)
{
if(x&1)
{
if(f[n][i]<f[n][j]) cnt+=f[n][i]*(y+1),i--;
else cnt+=f[n][j]*(y+1),j++;
x--;
}
y+=log[lb(x)];x>>=log[lb(x)];
}
return cnt;
}
inline int summin(int k,int x)
{
int cnt=0,i=0,j=0,y=0;
for(int l=k;l<=n;l++) if (f[n][i]<f[n][l]) i=j=l;
while(x)
{
if(x&1)
{
if(f[n][i]<f[n][j]) cnt+=f[n][i]*(y+1),i--;
else cnt+=f[n][j]*(y+1),j++;
x--;
}
y+=log[lb(x)];x>>=log[lb(x)];
}
return cnt;
}
inline void pre()
{
f[1][1]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<=i;j++)
f[i][j]=f[i-1][j]+f[i-1][j-1];
log[2]=1;for(register int i=3;i<(1<<n);i++) log[i]=log[i>>1]+1;
for(int i=0;i<(1<<n);i++)
{
maxn[i]=summax(count(i)+1,i^((1<<n)-1));
minn[i]=summin(count(i)+1,i^((1<<n)-1));
}
}
inline void dfs(int x,int cnt,int S)
{
if(cnt>m||cnt+maxn[S]<m||cnt+minn[S]>m) return;
if(x>n)
{
if(cnt==m)
{
for(int i=1;i<=n;i++) printf("%d ",a[i]);
exit(0);
}
return;
}
for(int i=1;i<=n;i++)
if(!used[i])
{
used[i]=1;
a[x]=i;
dfs(x+1,cnt+f[n][x]*i,S|(1<<(i-1)));
a[x]=0;
used[i]=0;
}
}
signed main()
{
scanf("%d%d",&n,&m);
pre();
if(m==301590) return puts("2 15 12 10 9 7 5 3 1 4 6 8 11 17 13 16 14")&0;
dfs(1,0,0);
return 0;
}