[HNOI2010]物品调度

看似很难

其实很水

仔细观察其实是两问。

第一问确定xi,yi,

posi=(ci+d*xi+yi) mod n不是白给的。

其实是同一个d*x+c的环上的所有点通过xi调整找到,yi的作用是更新到另一个环上去。

暴力枚举yi,每个环上用并查集维护紧跟着下一个可选择的

如果下一个被删除了,那么这个环已经用完,++yi

可以过。(因为数据水,zhoutb2333 dalao已经卡掉)

所以,考虑对环和环之间也用并查集维护一下,这样总的复杂度就是O(N)了

第二问更水

类似置换的问题做过很多次了。

找到置换环之后,由于必须和空位交换,所以含空位的len-1次,不含空位的len+1次(要把空位换进来多一次)

环与环之间交换是没有必要的。

一些值得注意的坑是:

对于这种取模的问题,ci,d上来直接对n取模了事。。

否则可能比n大,而并查集中未定义,或者直接RE

代码:(暴力枚举y)

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
#define int long long
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=100000+5;
int n,t,s;
int pos[N];
int q,p,m,d;
int c[N];
int fa[N];
int fin(int x){
    return fa[x]==x?x:fa[x]=fin(fa[x]);
}
bool dele[N];
bool vis[N];
int len;
int kil;
void init(){
    for(reg i=0;i<n;++i) fa[i]=i;
    memset(dele,0,sizeof dele);
    memset(pos,0,sizeof pos);
    memset(vis,0,sizeof vis);
    int go=(s+d)%n;
    fa[s]=go;dele[s]=1;
    ++kil;
    len=0;
}
int query(int st){
    int k=fin(st);
//    cout<<" kk "<<st<<" "<<d<<" : "<<k<<" "<<dele[k]<<" "<<(k+d)%n<<" "<<fin((k+d)%n)<<endl;
    if(!dele[k]){
        int lp=fin((k+d)%n);
        if(lp!=k) fa[k]=lp;
        dele[k]=1;
        ++kil;
        return k;
    }
    return -1;
}

void dfs(int x){
    vis[x]=1;++len;
    if(!vis[pos[x]]) dfs(pos[x]);
}
int main(){
    rd(t);
    while(t--){
        rd(n);rd(s);rd(q);rd(p);rd(m);rd(d);
        d%=n;
        init();
        c[0]=0;
        for(reg i=1;i<n;++i) c[i]=((ll)c[i-1]*q+p)%m;
        for(reg i=1;i<n;++i){
            c[i]%=n;
        //    cout<<" ii "<<i<<" "<<kil<<" "<<c[i]<<endl;
            int y=0;
            int tmp=0;
            while((tmp=query((c[i]+y)%n))==-1){
                ++y;
                //cout<<tmp<<" "<<y<<endl;
            }
            pos[i]=tmp;
        }
        pos[0]=s;
        int ans=0;
        for(reg i=0;i<n;++i){
            //cout<<pos[i]<<" ";
            if(!vis[i]) {
                len=0;
                if(pos[i]!=i){
                    dfs(i);
                    //cout<<" len "<<len<<endl;
                    if(i==0) ans+=len-1;
                    else ans+=len+1;
                }
            }
        }//cout<<endl;
        printf("%lld
",ans);
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2018/12/27 14:17:54
*/
View Code
原文地址:https://www.cnblogs.com/Miracevin/p/10185229.html