1998: Fsk物品调度 并查集

题意:给出一个数组 c[i] ,求一个数组 pos[i]=dxi+yi+c[i] 满足对于任意 j<i pos[i]!=pos[j] 。并且满足最小化 yi 的前提下最小化 xi 后面的不说了。

从前到后枚举,如果当前点没有被访问过,从当前点 i 开始枚举(i+d)%n ,这样会有一个环。

yi+1 时会从当前环转移到其他环,因此如果 c[i] 所对应的环上的点还有剩余那么从当前环上取一个点,否则增加 yi ,从其他环上选点。
可以用类似并查集的东西维护一下。

#include <bits/stdc++.h>
using namespace std;
#define N 110000
#define ll long long
int T,n,s,q,p,m,d;
int c[N],use[N],vis[N],pos[N],cnt[N],bel[N];
int fa[N],done[N];
int find(int x)
{
    if(cnt[bel[x]])return x==fa[x] ? fa[x]:fa[x]=find(fa[x]);   
    if(!done[x])done[x]=1,fa[x]=(x+1)%n;
    if(!cnt[bel[fa[x]]])
    {
        int ret=find(fa[x]);
        fa[x]=fa[fa[x]];
        return ret;
    }
    return find(fa[x]);
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        int ans=0;
        memset(use,0,sizeof(use));
        memset(vis,0,sizeof(vis));
        memset(done,0,sizeof(done));
        scanf("%d%d%d%d%d%d",&n,&s,&q,&p,&m,&d);
        c[0]=0;d%=n;pos[0]=s;
        if(!d)d++;

        for(int i=1;i<n;i++)c[i]=((ll)c[i-1]*q+p)%m;
        for(int i=0;i<n;i++)fa[i]=i;
        for(int i=0;i<n;i++)
            if(!use[i])
            {   
                cnt[i]=0;
                for(int j=i;!use[j];j=(j+d)%n)
                    use[j]=1,bel[j]=i,cnt[i]++;
            }
        fa[s]=(s+d)%n;cnt[bel[s]]--;
        for(int i=1,t;i<n;i++)
        {
            pos[i]=find(c[i]%n);
            if(--cnt[bel[pos[i]]])
                fa[pos[i]]=find((pos[i]+d)%n);
        }
        for(int i=0;i<n;i++)
            if(!vis[i])
            {
                vis[i]=1;int cnt=1,flag=0;
                if(!i)flag=2;
                for(int j=pos[i];!vis[j];j=pos[j])
                {
                    vis[j]=1;cnt++;
                    if(!j)flag=2;
                }
                if(cnt==1)continue;
                ans+=cnt+1-flag;
            }
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值