p1044韩信点兵

Posted 邱宇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了p1044韩信点兵相关的知识,希望对你有一定的参考价值。

数论好难啊~~ 

 

嗯这两道题看似题号、数据范围差的很多,其实有一些共通之处。

先来看一下韩信点兵:

 

  作为循环语句和判断语句的入门题,相信看我博客的肯定都会。

#include<iostream>
using namespace std;
int a,b,c,i;
int main()
{
    cin>>a>>b>>c;
    for(i=7+c;i<=100;i=i+7)
    {
        if((i%3==a)&&(i%5==b)&&(i>=10)&&(i<=100))
        {
            cout<<i<<endl;
            return 0;
        }
    }
    cout<<"No answer"<<endl;
return 0;
}
根本没必要贴出来的好吧

  下面来介绍一下直接算答案的强方法了。

  ans需要满足三个条件%3==a、%5==b,%7==c;

  那能不能构造出三个数,分别满足一个其中条件并且是另外两个数的公倍数?(这句话是本篇中最重要的话了,其他都是废话)

  比如满足第一个条件的数要求为5和7的倍数,也就是35的倍数。还要%3==a,现在35%3已经等于2了,难道要35*a/2?(我知道a只可能等1 2)不如往后找一找,说不定有%3=1的好数。然后70就是了,很棒。那第一个数就是70*a了。

  然后由于21%5==1,15%7==1,刚好。那么最后答案就是(70*a+21*b+15*c)%105。

  本题中要求10到100之间的,加个判断就行。

 1 #include<iostream>
 2 using namespace std;
 3 int a,b,c,ans;
 4 int main()
 5 {
 6     cin>>a>>b>>c;
 7     ans=(70*a+21*b+15*c)%105;
 8     if(ans>=10&&ans<=100) cout<<ans;
 9     else cout<<"No answer"<<endl;
10 return 0;
11 }

这道题的思想再推广一点会怎么样呢?那就是p1898了。

看不懂题解怎么办啊?没关系,往下看。

我们先处理出所有的a的累乘sum(应该不是sum吧但是我不知道用什么),对每个数找出sum/a[i]的倍数中%a[i]==1的,乘对应的b[i]是满足第i个条件的数。全部相加后对sum取余即为所求。\\

果然还是看不懂就对着代码看.

这个代码的复杂度好迷啊...如果要写的话还是学一下exgcd吧(18/12/10);

#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
int i,f;
long long wyt(long long x,long long y,long long z)
{
    if(y==1)return 0;
    for(f=0;;f++)
        if(x*f%y==1)break;
    return f*x*z;
}
long long ans,sum=1;
int n;
long long a[11],b[11];
int main()
{
//freopen("123.in","r",stdin);
//freopen("123.out","w",stdout);
    cin>>n;
    for(i=1;i<=n;i++)
    {    
        cin>>a[i]>>b[i];
        sum*=a[i];
    }
    for(i=1;i<=n;i++)
    {
        ans+=wyt(sum/a[i],a[i],b[i]);
    }
    cout<<ans%sum;
}

由于数较少,就不用快读了哈。

 

以上是关于p1044韩信点兵的主要内容,如果未能解决你的问题,请参考以下文章

P1044 栈 卡特兰数/记忆化搜索

韩信点兵 ACM 代码问题。

洛谷——P1044 栈

洛谷 P1044 栈

洛谷P1044 栈(Catalan数)

韩信点兵