uva12174 shuffle【方法二】

这篇博客探讨了音乐播放器的洗牌功能,如何根据已播放的歌曲历史推断未来的洗牌可能发生的点。内容涉及到算法分析,通过输入歌曲总数和历史记录,找出合法的未来洗牌位置。如果历史记录不符合洗牌算法,则输出0。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

You are listening to your music collection using the shuffle function
to keep the music surprising. You assume that the shuffle algorithm of
your music player makes a random permutation of the songs in the
playlist and plays the songs in that order until all songs have been
played. Then it reshuffles and starts playing the list again. You have
a history of the songs that have been played. However, your record of
the history of played songs is not complete, as you started recording
songs at a certain point in time and a number of songs might already
have been played. From this history, you want to know at how many
different points in the future the next reshuffle might occur. A
potential future reshuffle position is valid if it divides the
recorded history into intervals of length s (the number of songs in
the playlist) with the rst and last interval possibly containing less
than s songs and no interval contains a specic song more than once.
Input On the rst line one positive number: the number of testcases, at
most 100. After that per testcase: One line with two integers s and
n (1 s;n 100000): the number of different songs in the playlist
and the number of songs in the recorded playlist history. One line
with n space separated integers, x 1 ;x 2 ;:::;x n (1 x i s ): the
recorded playlist history. Output Per testcase: One line with the
number of future positions the next reshuffle can be at. If the
history could not be generated by the above mentioned algorithm,
output 0 .

排除掉所有不可能的答案,剩下的便是解。
如果一个答案不可能,那么一定是把两个相同的数放在了同一个区间里。考虑每一对相邻的相同的且间距小于s的数,则他们之间一定被划开。那么除了他们之间的界线,其他界线一定是非法的【因为会把他们两个划在一起】。
注意排除掉连续区间时的循环问题。

方法一见这里

#include<cstdio>
#include<cstring>
#define M(a) memset(a,0,sizeof(a))
int fir[100010],ne[100010],a[100010];
bool b[100010];
int main()
{
    int i,j,k,m,n,p,q,x,y,z,T,tot,ans,s,l,r;
    scanf("%d",&T);
    while (T--)
    {
        M(fir);
        M(ne);
        M(a);
        memset(b,1,sizeof(b));
        scanf("%d%d",&s,&n);
        for (i=1;i<=n;i++)
          scanf("%d",&a[i]);
        for (i=n;i>=1;i--)
        {
            ne[i]=fir[a[i]];
            fir[a[i]]=i;
        }
        for (k=1;k<=s;k++)
        {
            for (i=fir[k];ne[i];i=ne[i])
            {
                if (ne[i]-i>=s) continue;
                l=i%s;
                r=(ne[i]%s-1+s)%s;
                if (l<=r)
                {
                    for (j=0;j<l;j++) b[j]=0;
                    for (j=r+1;j<s;j++) b[j]=0;
                }
                else
                  for (j=r+1;j<l;j++) b[j]=0;
            }
        }
        ans=0;
        for (i=0;i<s;i++)
          if (b[i]) ans++;
        printf("%d\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值