HDU 4669 Mutiples on a circle (2013多校联合7 1004)

http://acm.hdu.edu.cn/showproblem.php?pid=4669


Mutiples on a circle

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 767    Accepted Submission(s): 209


Problem Description
Tom has a necklace with n jewels. There is a number on each jewel. Now Tom wants to select a wonderful chain from the necklace. A chain will be regarded wonderful if the wonderful value of the chain is a multiple of a key number K. Tom gets the wonderful value using this way:He writes down the number on the chain in clockwise order and concatenates them together. In this way, he gets a decimal number which is defined as the wonderful value.
For example, consider a necklace with 5 jewels and corresponding numbers on the jewels are 9 6 4 2 8 (9 and 8 are in neighborhood). Assume we take K=7, then we can find that only five chains can be multiples of K. They are 42, 28, 896, 42896 and 89642.

Now Tom wants to know that how many ways he can follow to select a wonderful chain from his necklace.
 

Input
The input contains several test cases, terminated by EOF.
Each case begins with two integers n( 1 ≤ n ≤ 50000), K(1 ≤ K ≤ 200),the length of the necklace and the key number.
The second line consists of n integer numbers, the i-th number a i(1 ≤ a i ≤ 1000) indicating the number on the ith jewel. It’s given in clockwise order.
 

Output
For each test case, print a number indicating how many ways Tom can follow to select a wonderful chain.

思路:我们首先可以先将环变成一条链,比如原来是 9 6 4 2 8,变成一条链后是 9 6 4 2 8 9 6 4 2,然后设原环有n个珠子,设dp[i][j]表示以第i个珠子结尾,向前最多包含n个珠子,组成的数模k余j的数量。(这里的第i个是指的链中的第i个,我们从第n个开始),比如对于样例,以8结尾的就包括5种情况 8,28,428,6428,96428,五种情况,以9结尾的就有9,89,289,4289,64289,五种情况,其他易推之,我们首先暴力将以8结尾的所有情况O(n)地求出来,(这个太简单了就不说了),然后考虑怎么快速地转移到以9为结尾的方案,现在我们知道了以8结尾的所有状态,为了方便叙述,这里用V8代替以8结尾的方案,V9代替以9为结尾的方案。

易知,对于V8,除了96428这种情况,其他(n-1)中情况均可以直接转移个V9,即8->89,28->289,428->4289,6428->64289,那么对于这n-1中情况我们可以按模k分成k种情况,以O(k)的复杂度转移,即dp[i-1][j]->dp[i][(j*10+9)%k],最后还要减去96428这种情况,然后加上单独的9组成的情况,则我们完成了转移,最后得到V9。


如果您已经理解了前面的例子,那么这道题您已经做出了90%了,那还有10%是什么呢?

这里要注意的是珠子的权值的范围是1到1000,所以我们在做这一步转移的时候(dp[i-1][j]->dp[i][(j*10+9)%k])不能乘10,而是要乘以10^len,这里的len是指第i个数的十进制位数,这个可以通过与处理得到。

另外,由于我们转移的时候需要的信息仅仅是前一位的信息,所以我们不用设置dp[50000][200]这么大的空间,而是可以采用滚动数组的思想,交换使用空间,可以节省大量空间。

以上是整体思路,代码实现还有一些小的细节,具体实现可以参考下面的代码。



#include <string.h>
#include <stdio.h>
#include <algorithm>
#define maxn 50010
#define ll long long
using namespace std;
int getlen(int x)
{
    int sum=1;
    while(x/10)
    {
        sum++;
        x/=10;
    }
    return sum;
}
int pow[200010];
int a[maxn],len[maxn];
int cout[2][210];
void init(int n,int mod)
{
    int i;pow[0]=1;
    for(i=1;i<=n;i++)
    pow[i]=(pow[i-1]*10)%mod;
}
int main()
{
  //  freopen("dd.txt","r",stdin);
    int n,k;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        int i;
        memset(cout,0,sizeof(cout));
        init(n*4,k);
        for(i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            len[i]=getlen(a[i]);
        }
        a[n]=a[0];
        len[n]=len[0];
        ll ans=0;
        int le=0,sum=0;
        for(i=n;i>0;i--)
        {
            sum=(a[i]*pow[le]+sum)%k;
            cout[0][sum]++;
            le+=len[i];
        }
        ans+=cout[0][0];
        int t=1;
        for(i=1;i<n;i++)
        {
            memset(cout[t],0,sizeof(cout[t]));
            for(int j=0;j<k;j++)
            {
                cout[t][(j*pow[len[i]]+a[i])%k]+=cout[1-t][j];
            }
            sum=(sum*pow[len[i]]+a[i])%k;
            cout[t][sum]--;
            cout[t][a[i]%k]++;
            ans+=cout[t][0];
            t=1-t;
            sum=((sum-a[i]*pow[le])%k+k)%k;
        }
        printf("%I64d\n",ans);

    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值