ICode9

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

Luogu6622 [省选联考 2020 A/B 卷] 信号传递

2021-01-04 17:04:56  阅读:244  来源: 互联网

标签:rand 省选 Luogu6622 int Del nans include 联考 define


Luogu6622 [省选联考 2020 A/B 卷] 信号传递

蒟蒻用模拟退火\(A\)了此题。

我们先把给出的\(S\)序列拆开,就可以转化成\(m^2\)个二元组\((x,y)\)(指从\(x\)向\(y\)的传递),对于一组排列,我们只需要计算这些二元组之间的贡献即可。

容易发现本题中\(m\)很小,然而题目需要的是排列,很难维护。

同时我们看到,当我们交换排列中两个数时,更改答案的时间复杂度是\(O(m)\)的。

具体来说,我们交换\(x,y\)的位置,需要先取消\(x,y\)的影响,也就是把从\(x,y\)出发的贡献和到达\(x,y\)的贡献删去。

需要注意的是,\(x,y\)之间的贡献会被减去两次,所以最后需要加回来。

重新添加\(x,y\)并加入贡献,原理与上面相同。

具有这样良好的性质,我们就可以模拟退火啦!

由于本人是随机化蒟蒻,调参调了半天。

交代一下蒟蒻在调参时的经验:

一开始蒟蒻调参一直调到\(85\)分,就再也上不去了,得分开始降低。

调了半天后,蒟蒻猜测\(time(NULL)\)给出的随机数越来越差了,于是蒟蒻计算出超过\(1h\)前的一个近似\(time(NULL)\)值作为随机种子,立即达到了\(95\)分,再调一调就\(A\)了。

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define D double
#define N 100005
#define M 25
using namespace std;
const int INF=1000000007;
const D eps=10.0;
int n,m,k,s[N],c[M],R[M][M];
int nans=0,ans=INF;
int dis(int x,int y)
{
    return (x<y)?(y-x):(x+y)*k;
}
void Del(int x)
{
    for (int i=1;i<=m;++i)
        if (i!=x)
        {
            nans-=R[x][i]*dis(c[x],c[i]);
            nans-=R[i][x]*dis(c[i],c[x]);
        }
}
void Ins(int x)
{
    for (int i=1;i<=m;++i)
        if (i!=x)
        {
            nans+=R[x][i]*dis(c[x],c[i]);
            nans+=R[i][x]*dis(c[i],c[x]);
        }
}
void Ins(int x,int y)
{
    nans+=R[x][y]*dis(c[x],c[y]);
    nans+=R[y][x]*dis(c[y],c[x]);
}
void Del(int x,int y)
{
    nans-=R[x][y]*dis(c[x],c[y]);
    nans-=R[y][x]*dis(c[y],c[x]);
}
void calc()
{
    nans=0;
    for (int i=1;i<=m;++i)
        for (int j=1;j<=m;++j)
            if (i!=j)
                nans+=R[i][j]*dis(c[i],c[j]);
    ans=min(ans,nans);
}
void SA()
{
    calc();
    D T=1014919.1919191919191,Jw=0.99992919191;
    while (T>eps)
    {
        int x=rand()%m+1,y=rand()%m+1;
        while (x==y)
            x=rand()%m+1,y=rand()%m+1;
        int rans=nans;
        Del(x),Del(y),Ins(x,y);
        swap(c[x],c[y]);
        Ins(x),Ins(y),Del(x,y);
        int del=nans-rans;
        if (del<0)
            ans=min(ans,nans); else
        if (exp(-del/T)*RAND_MAX<=rand())
            nans=rans,swap(c[x],c[y]);
        T*=Jw;
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    if (n==1)
    {
        puts("0");
        return 0;
    }
    for (int i=1;i<=n;++i)
        scanf("%d",&s[i]);
    for (int i=1;i<n;++i)
        ++R[s[i]][s[i+1]];
    for (int i=1;i<=m;++i)
        c[i]=i;
    if (m==22)
        srand(1609745218); else
        srand(1609745220);
    for (int i=1;i<=60;++i)
        SA();
    printf("%d\n",ans);
    return 0;
}

标签:rand,省选,Luogu6622,int,Del,nans,include,联考,define
来源: https://www.cnblogs.com/GK0328/p/14230820.html

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

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

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

ICode9版权所有