UVA 11754 (暴力+中国剩余定理)

题目链接http://www.bnuoj.com/v3/problem_show.php?pid=20172

题目大意:有C个模方程,每个方程可能有k余数,求最小的S个解。

解题思路

看见模方程就想到中国剩余定理,然后看下确定的方程情况。

由乘法原理,共有II ki 种情况,即求解II ki 次。k比较大时基本完蛋。

其实解模方程还有一种暴力方法,就是选定一个模方程,令t=0,1...., n=t*LCM+余数(n一定要大于0)

通过t不断增大这种迭代方式从小到大创造一些可能解n,然后去测试其它方程,看余数对不对。

如果余数全对,那么就找到了一个解。否则就砍掉。

因为测试是很快的,大部分数据一开始就被砍了,所以k比较大时速度非常快。

 

毕竟上面是看RP的暴力,所以设定一个分界(10000),如果II ki <10000 ,那么还是通过中国剩余定理来求解,复杂度O(n)。

方法就是DFS枚举出C个余数情况,然后求解。

由于求出的全是最小整数解,S比较大时,剩余定理的解可能不足,这时候从小到大每个值加M的倍数凑出更大的解。

 

#include "cstdio"

#include "set"

#include "vector"

#include "algorithm"

using namespace std;

#define LL long long

#define LIMIT 10000

int C,S,s;

LL m[15],k[15],y[15][105],a[15],M;

set<LL> value[15];

vector<LL> ans;

void solve_violence(int bc)

{

    for(int i=1;i<=C;i++)

    {

        value[i].clear();

        if(i!=bc) for(int j=1;j<=k[i];j++) value[i].insert(y[i][j]);

    }

   for(int t=0;S!=0;t++)

    {

        for(int i=1;i<=k[bc];i++)

        {

            LL n=t*m[bc]+y[bc][i];

            if(!n) continue;

            bool ok=true;

            for(int j=1;j<=C;j++)

            {

                if(j==bc) continue;

                if(!value[j].count(n%m[j])) {ok=false;break;}

            }

            if(ok) {printf("%lld\n",n);if(--S==0) return;}

        }

    }

}

LL ex_gcd(LL a,LL b,LL &x,LL &y)

{

    if(a==0&&b==0) return -1;

    if(b==0) {x=1;y=0;return a;}

    LL d=ex_gcd(b,a%b,y,x);

    y-=a/b*x;

    return d;

}

LL solve_china()

{

    LL res=0;M=1;

    for(int i=1;i<=C;i++) M*=m[i];

    for(int i=1;i<=C;i++)

    {

        LL w=M/m[i],x,y;

        ex_gcd(m[i],w,x,y);

        y=(y*w%M+M)%M;

        res=(res+y*a[i])%M;

    }

    return res;

}

void dfs(int dep)

{

    if(dep>C)

    {

        ans.push_back(solve_china());

        return;

    }

    for(int i=1;i<=k[dep];i++)

    {

        a[dep]=y[dep][i];

        dfs(dep+1);

    }

}

int main()

{

    //freopen("in.txt","r",stdin);

    while(scanf("%d%d",&C,&S)&&C)

    {

        int bestc=1;ans.clear();s=S;M=1;

        LL tot=1;

        for(int i=1;i<=C;i++)

        {

            scanf("%lld%lld",&m[i],&k[i]);

            tot*=k[i];

            if(k[i]*m[bestc]<k[bestc]*m[i]) bestc=i;

            for(int j=1;j<=k[i];j++)  scanf("%lld",&y[i][j]);

            sort(y[i]+1,y[i]+1+k[i]);

        }

        if(tot<LIMIT)

        {

            dfs(1);

            sort(ans.begin(),ans.end());

            for(int t=0;S!=0;t++)

                for(int i=0;i<ans.size();i++)

            {

                LL n=t*M+ans[i];

                if(n>0)

                {

                    printf("%lld\n",n);

                    if(--S==0) break;

                }

            }

        }

        else solve_violence(bestc);

        printf("\n");

    }

}

 

neopenx 445520 20172 Accepted GNU C++ 26 ms   2223 B 2015-02-06 23:10:03

你可能感兴趣的:(uva)