码迷,mamicode.com
首页 > 其他好文 > 详细

p1825

时间:2018-08-11 15:34:22      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:color   mem   正数   for   维护   pen   有趣的   --   else   

技术分享图片

本题是一个有趣的有后效性的题目,如果是考察n个数能否等于x大家肯定都会,背包嘛。

但是能否被x整除改怎么写呢?原来的状态不满足后无效性啊。考虑到x较小,最直接的方法就是增加一个维度。

维护一个flag[i][f]表示第i个数时能否组成%x==f,他的转移方程是

flag[0][0]=1;
flag[i][f]=flag[i-1][f-o[i]]||flag[i-1][f+o[i]];

但是f如果小于o[i]呢?如果f+o[i]大于x了呢?就很尴尬。

这个时候就要巧妙的运用模运算了。

其实我是从flag[i-1][f]出发,如果flag[i-1][f]==1,就可以更新加减o[i]的答案了。可以这样写。

if(flag[i-1][f])
    flag[i][((f-t)%x+x)%x]=flag[i][(f+t)%x]=1;

减的时候先不管会不会小于0,就先减一下o[i],然后对x取余。如果是负数也不会小于-x,那就再加上一个x;然而如果减一下还是一个正数的话现在就会大于x,那就再模一次x呗。

加的时候就加一下后对x取余就好了。

 复杂度是O(k*n*x)。

int i,f,t;
int k,n,x;
bool flag[21000][210];
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
//freopen("123.in","r",stdin);
//freopen("123.out","w",stdout);
    cin>>k;
    for(;k>0;k--)
    {
        cin>>n>>x;
        memset(flag,0,sizeof(flag));
        flag[0][0]=1;
        for(i=1;i<=n;i++)
        {
            cin>>t;
            for(f=0;f<x;f++)
                if(flag[i-1][f])
                    flag[i][((f-t)%x+x)%x]=flag[i][((f+t)%x+x)%x]=1;
        }
        if(flag[n][0])cout<<"Divisible"<<endl;
        else          cout<<"Not divisible"<<endl;
    }
}

 

p1825

标签:color   mem   正数   for   维护   pen   有趣的   --   else   

原文地址:https://www.cnblogs.com/qywyt/p/9459665.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!