首页 > 其他 > 详细

p1825

时间:2018-08-11 15:07:31      阅读:152      评论:0      收藏:0      [点我收藏+]

技术分享图片

本题是一个有趣的有后效性的题目,如果是考察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

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

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!