zoukankan      html  css  js  c++  java
  • p1825

    本题是一个有趣的有后效性的题目,如果是考察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;
        }
    }
  • 相关阅读:
    动态规划——E (LIS())最长上升子序列
    动态规划——F 最大矩阵和
    动态规划——I 记忆化搜索
    动态规划——C编辑最短距离
    动态规划——K背包问题
    动态规划——H 最少回文串
    动态规划——G 回文串
    动态规划——J 括号配对问题
    Codeforces4D
    UVa10635
  • 原文地址:https://www.cnblogs.com/qywyt/p/9459665.html
Copyright © 2011-2022 走看看