P14148 错觉 题解
TimSwn090306 · · 题解
跑个暴力发现有解情况下,解的数量是比较多的。
于是直接模拟退火!令
对于有解的情况,上述参数的模拟退火可以在本题数据中以不到
代码如下:
#include <bits/stdc++.h>
#define fin(str) freopen(str,"r",stdin)
#define fout(str) freopen(str,"w",stdout)
#define ll long long
using namespace std;
bool MEM_beg;
const int maxn=1e6+5;
const double down=0.9997;
const double eps=1e-9;
int n,k,res,p[maxn];
inline int val(int x){
int cur=0;
for (int i=23;~i;i--){
if ((x>>i)&1) cur++;
}
return cur;
}
inline void SA(){
double T=10000;
while (T>eps && res){
int x=rand()%n+1,y=rand()%n+1;
while (n>1 && x==y) y=rand()%n+1;
int res2=res;
res2^=((p[x]+k*x)^(p[y]+k*y));
res2^=((p[y]+k*x)^(p[x]+k*y));
if (val(res2)<=val(res) || (exp(-T/(val(res2)-val(res)))*RAND_MAX>rand())){
swap(p[x],p[y]);
swap(res,res2);
}
T*=down;
}
}
bool MEM_end;
int main(){
srand(time(0));
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++) p[i]=n-i+1;
for (int i=1;i<=n;i++) res^=(p[i]+k*i);
clock_t st=clock();
while (res && (double)(clock()-st)/CLOCKS_PER_SEC<=0.08) SA();
if (!res) for (int i=1;i<=n;i++) printf("%d ",p[i]);
else printf("-1\n");
cerr<<"\nMemory : "<<1.0*abs(&MEM_end-&MEM_beg)/1048576<<" MB\n";
return 0;
}
比较有趣的是,令