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);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);
                    if(--S==0) break;
                }
            }
        }
        else solve_violence(bestc);
        printf("
");
    }
}
neopenx 445520 20172 Accepted GNU C++ 26 ms   2223 B 2015-02-06 23:10:03
原文地址:https://www.cnblogs.com/neopenx/p/4278197.html