16.7.25

数论基础

快速乘转载

快速乘法的思想和快速幂的思想一样,快速幂是求一个数的高次幂,快速乘法是求两个数相乘,什么时候才用得到快速乘法呢,当两个数相乘可能超过long long (大约10的18次方)范围的时候用,因为在加法运算的时候不会超,而且可以直接取模,这样就会保证数据超不了了。

LL fast_multi(LL m, LL n, LL mod)//快速乘法
{
    LL ans = 0;//注意初始化是0,不是1 
    while (n)
    {
        if (n & 1)
            ans += m;
        m = (m + m) % mod;//和快速幂一样,只不过这里是加
        m %= mod;//取模,不要超出范围 
        ans %= mod;
        n >>= 1;
    }
    return ans;
}

在快速幂中使用快速乘

LL fast_pow(LL a, LL n, LL mod)//快速幂 
{
    LL ans = 1;
    while (n)
    {
        if (n & 1)
            ans = fast_multi(ans, a, mod);//不能直接乘 
        a = fast_multi(a, a, mod);
        ans %= mod;
        a %= mod;
        n >>= 1;
    }
    return ans;
}

素数线性筛法

如果我们知道一个数p是质数,那么我们可以确定k*p都不是质数,k=2,3…,相对的,如果一个数p满足小于他的数都没有指出他不是质数,那么他是个质数。

for(int i = 2; i < 1000; i++)
{
    if(!f[i])
    {
        prime[cnt++] = i;
        for(int j = 2; i*j < 1000; j++) f[i*j] = 1; 
    }
}

SG函数转载

给定一个有向无环图和一个起始顶点上的一枚棋子,两名选手交替的将这枚棋子沿有向边进行移动,无法移动者判负。

任何一个Impartial Combinatorial Games都可以通过把每个局面看成一个顶点,对每个局面和它的子局面连一条有向边来抽象成这个“有向图游戏”。下 面我们就在有向无环图的顶点上定义Sprague-Grundy函数。

首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。

对于一个给定的有向无环图,定义关于图的每个顶点的Sprague-Grundy函数g如下:g(x)=mex{ g(y) | y是x的后继 },这里的g(x)即sg[x]

例如:取石子问题,有1堆n个的石子,每次只能取{1,3,4}个石子,先取完石子者胜利,那么各个数的SG值为多少?

sg[0]=0,f[]={1,3,4},

x=1时,可以取走1-f{1}个石子,剩余{0}个,mex{sg[0]}={0},故sg[1]=1;

x=2时,可以取走2-f{1}个石子,剩余{1}个,mex{sg[1]}={1},故sg[2]=0;

x=3时,可以取走3-f{1,3}个石子,剩余{2,0}个,mex{sg[2],sg[0]}={0,0},故sg[3]=1;

x=4时,可以取走4-f{1,3,4}个石子,剩余{3,1,0}个,mex{sg[3],sg[1],sg[0]}={1,1,0},故sg[4]=2;

x=5时,可以取走5-f{1,3,4}个石子,剩余{4,2,1}个,mex{sg[4],sg[2],sg[1]}={2,0,1},故sg[5]=3;

以此类推…..

x 0 1 2 3 4 5 6 7 8….

sg[x] 0 1 0 1 2 3 2 0 1….

计算从1-n范围内的SG值。

f(存储可以走的步数,f[0]表示可以有多少种走法)

f[]需要从小到大排序

1.可选步数为1~m的连续整数,直接取模即可,SG(x) = x % (m+1);

2.可选步数为任意步,SG(x) = x;

3.可选步数为一系列不连续的数,用GetSG()计算

模板1如下(SG打表):

//f[]:可以取走的石子个数
//sg[]:0~n的SG函数值
//hash[]:mex{}
int f[N],sg[N],hash[N];     
void getSG(int n)
{
    int i,j;
    memset(sg,0,sizeof(sg));
    for(i=1;i<=n;i++)
    {
        memset(hash,0,sizeof(hash));
        for(j=1;f[j]<=i;j++)
            hash[sg[i-f[j]]]=1;
        for(j=0;j<=n;j++)    //求mes{}中未出现的最小的非负整数
        {
            if(hash[j]==0)
            {
                sg[i]=j;
                break;
            }
        }
    }
}

模板2如下(dfs):

//注意 S数组要按从小到大排序 SG函数要初始化为-1 对于每个集合只需初始化1遍
//n是集合s的大小 S[i]是定义的特殊取法规则的数组
int s[110],sg[10010],n;
int SG_dfs(int x)
{
    int i;
    if(sg[x]!=-1)
        return sg[x];
    bool vis[110];
    memset(vis,0,sizeof(vis));
    for(i=0;i<n;i++)
    {
        if(x>=s[i])
        {
            SG_dfs(x-s[i]);
            vis[sg[x-s[i]]]=1;
        }
    }
    int e;
    for(i=0;;i++)
        if(!vis[i])
        {
            e=i;
            break;
        }
    return sg[x]=e;
}

组合数学

排列
从N个元素中,取出R个元素按顺序排成一列,称为从N中取出R的排列,他的方案数表示为P(N,R);

P(N,R) = N!/(N-R)!

组合
从N个元素中,任意取出R个元素为一组倘若不考虑取出的顺序,则称为从N中取出R的组合,他的方案数表示为C(N,R);

C(N,R) = P(N,R)/R!

LUCAS定理

C(n,m)%p = C(n/p,m/p)*C(n%p,m%p)%p;
当p比较小的时候,通过LUCAS定理能够明显减少求C(n,m)的时间复杂度。

欧几里得算法

也就是辗转相除法,用于求两个非负整数的最大公约数
gcd(a,b) = gcd(b,a mod b)

扩展欧几里得算法用于解对于给定的a,b,方程ax+by=gcd(a,b)=d的一组解(x,y)。
根据裴蜀定理:
a/d*x+b/d*y=1有解,且有无数组解,将两边同乘d就可以得到上式。

我们回想我们求gcd(a,b)的过程:当发现a=gcd,b=0的时候,停止计算,显然此时x=1,y=0,即可满足上述方程。
于是我们得到了扩展欧几里得算法的递归做法:

    int exGcd(int a , int b, int &x, int &y)
    {
        if(b == 0)
        {
            x = 1;
            y = 0;
            return a;
        }
        int d = exGcd(b, a%b,y,x);
        y-=a/b*x;
        return d;
    }

所求得的x,y,分别是a%b,b%a的乘法逆元。

中国剩余定理(孙子定理)(转载

韩信带1500名兵士打仗,战死四五百人,站3人一排,多出2人;站5人一排,多出4人;站7人一排,多出6人。韩信马上说出人数:1049。

显然这个问题我们可以暴力枚举解决,但是如果数字很大,限制条件很多呢?

设正整数m1,m2,…,mk两两互素,则同余方程组

这里写图片描述

有整数解,并且在模 M = m1×m2×…×mk 下的解是唯一的,解为

这里写图片描述

其中 Mi = M/mi , Mi^-1 为 Mi % mi 的逆元

int CRT(int a[],int m[],int n)  
{  
    int M = 1;  
    int ans = 0;  
    for(int i=1; i<=n; i++)  
        M *= m[i];  
    for(int i=1; i<=n; i++)  
    {  
        int x, y;  
        int Mi = M / m[i];  
        exGcd(Mi, m[i], x, y);  
        ans = (ans + Mi * x * a[i]) % M;  
    }  
    if(ans < 0) ans += M;  
    return ans;  
}

欧拉函数

欧拉函数用希腊字母φ表示,φ(N)表示N的欧拉函数.

对φ(N)的值,我们可以通俗地理解为小于N且与N互质的数的个数.

φ(N)=N×(1-1/p1)×(1-1/p2)×…×(1-1/pn). 其中,p1..pn是x的所有质因数,N不为0。

欧拉函数是积性函数,但不是完全积性函数,即φ(mn)=φ(n)*φ(m)只在(n,m)=1时成立.

O(n)复杂度的同时求素数+欧拉函数的模板:

    for(phi[1] = 1,int i = 2; i <= Maxn ; i++)
    {
        if(!f[i]) prime[top++] = i,phi[i] = i-1;
        for(int j = 0; j < top && i*prime[j] <= Maxn; j++)
        {
            f[i*prime[j]] = 1;
            if(i%prime[j]) 
                phi[i*prime[j]] = phi[i]*(prime[j]-1);
            else
            {
                phi[i*prime[j]] = phi[i]*prime[j];
                break;
            }
        }
    }

//今日代码
Fzu 7月25日专题训练

D - Biorhythms

(x 同余 a%23 同余 b%28 同余 c%33 中国剩余定理. 感觉用枚举应该也行..)

#include<iostream> 
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
#define LL long long 
#define INF 0x1f1f1f1f
using namespace std;

int arr[3];
int m[3];

void exGcd(int a, int b, int &x ,int &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return ;
    }
    exGcd(b,a%b,y,x);
    y-=a/b*x;
}

int crt(int a[],int m[],int n)
{
    int M = 1;
    int ans = 0;
    for(int i = 0; i < n; i++)
        M *= m[i];
    for(int i = 0; i < n; i++)
    {
        int x,y;
        int Mi = M / m[i];
        exGcd(Mi,m[i],x,y);
        ans = (ans + Mi*x*a[i]) % M;
    }
    if(ans < 0) ans+=M;
    return ans;
}

int main()
{
    freopen("xx.in","r",stdin);
    freopen("xx.out","w",stdout);

    int k = 21252;
    m[0] = 23;
    m[1] = 28;
    m[2] = 33;

    int a,b,c,d;
    int cnt = 0; 
    while(cin >> a >> b >> c >> d && !(a==-1&&b==-1&&c==-1&&d==-1))
    {
        cnt++;

        arr[0] = a;
        arr[1] = b;
        arr[2] = c;

        int n = crt(arr,m,3)-d;
        if(n <= d) n+=k;

        cout << "Case " << cnt << ": the next triple peak occurs in "<< n <<" days."<< endl;

    }

    return 0;
}

E - Benefit

(求能使得a和b的最小公倍数为c的最小b。当c不能除断a时必然不存在。要满足条件,a与b的公约数为1。gcd(c/a,a)若不为1,则从a中把其扣除,直到为1,此时c/a即为答案)

#include<iostream> 
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
#define LL long long 
#define INF 0x1f1f1f1f
using namespace std;

int gcd(int a,int b)
{
    if(a < b) return gcd(b,a);
    else
        return a%b==0?b:gcd(b,a%b);

}

int main()
{
    freopen("xx.in","r",stdin);
    freopen("xx.out","w",stdout);

    int t;
    cin >> t;
    while(t--)
    {
        int a, c;
        cin >> a >> c;

        if(c%a) 
        {
            cout << "NO SOLUTION" << endl;
            continue;
        }

        int g = 1;
        while(1)
        {
            a = a/g;
            g = gcd(c/a,a);
            if(g == 1) break;
        }
        cout << c/a << endl;
    }

    return 0;
}

F - 青蛙的约会

(两只青蛙分别从x和y出发,跳一个长度为L的环,青蛙A一次能跳m米,青蛙B一次能跳n米,问要几次跳跃后能见面。扩展欧几里得定律,两只青蛙跳的次数一致,(?m+x)%L = (?n+y)%L。
设过s步后两青蛙相遇,则必满足等式: (x+m×s)-(y+n×s)=k×L(k=0,1,2….)
变形得 (n-m)×s+k×L=x-y
令n-m=a,k=b,x-y=c,即 a×s+b×L=c
只要上式存在整数解,则两青蛙能相遇,且步数为s,否则不能)

#include<iostream> 
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
#define LL long long 
#define INF 0x1f1f1f1f
using namespace std;

void exgcd(LL a,LL b,LL &d,LL &x,LL &y) 
{
    if(b == 0)
    {
        d = a;
        x = 1;
        y = 0;
        return ;
    }
    exgcd(b,a%b,d,y,x);
    y-=a/b*x;
}

int main()
{
    freopen("xx.in","r",stdin);
    freopen("xx.out","w",stdout);

    LL x,y,m,n,L;
    cin >> x >> y >> m >> n >> L;
    LL d,xx,yy;

    exgcd(n-m,L,d,xx,yy);
    int b = L/d;
    int t = (x-y)/d;

    if((x-y)%d)
        cout << "Impossible" << endl;
    else
    {
        xx = xx*t;
        xx = (xx%b + b) % b;
        cout << xx << endl;
    }

    return 0;   
}

H - How do you add?

(n=1 k=k时为k种,n=n,k=1时为1种。一般的情况是,arr[n][k]可视作n-1,k不变和k-1,n不变两种情况的和(由前一种的每个情况+1,后一种的每个情况+0得到)。 另一种解法是,看做C(n+k-1,k-1)的组合数,如果没有可加0的情况,相当于隔板问题,n个物品隔成k块,有加0的情况则再多k个0一起隔。)

#include<iostream> 
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
#define LL long long 
#define INF 0x1f1f1f1f
using namespace std;

int arr[110][110];//n由k个数组成 

int main()
{
    freopen("xx.in","r",stdin);
    freopen("xx.out","w",stdout);

    for(int i = 1; i < 110; i++)
    { 
        arr[1][i] = i;
        arr[i][1] = 1;
    } 

    for(int i = 2; i < 110; i++)
        for(int j = 2; j < 110; j++)
            arr[i][j] = (arr[i-1][j] + arr[i][j-1])%1000000;



    int n,k;
    while(cin >> n >> k && !(n == 0 && k == 0))
    {
        cout << arr[n][k] << endl;
    }

    return 0;   
}

I - Matches Game

(有m堆火柴,每堆火柴的根数给定,每次可以从任意堆中拿取任意根火柴,最后没火柴拿的一方输,问先手能否获胜。1堆能一次拿光于是获胜,2堆若相同数量,则无论先手怎么拿后手都拿另一堆相同数目的,于是先手必输,但如果不同数量,先手可以在第一次先拿成两堆相同的,然后把鸡肋丢给对方,则先手比胜。3堆情况就更复杂。但大致可以看出有一个【多出】的问题,如果这些堆火柴有【多出】,那就可以把【多出】拿走然后鸡肋丢给对方,先手必赢。如果恰好持平没有【多出】,则先手必输。(火柴数全部异或判持平还是多出))

#include<iostream> 
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
#define LL long long 
#define INF 0x1f1f1f1f
using namespace std;

int main()
{
    freopen("xx.in","r",stdin);
    freopen("xx.out","w",stdout);

    int n;
    while(cin >> n)
    {
        int ans =0;
        for (int i =0; i < n; i++)
        {
            int a;
            cin >> a;
            ans = ans ^ a;
        }
        if (ans) printf("Yes\n");
        else printf("No\n");
    }

    return 0;   
}

J - A Funny Game

(由于能把环分为两条链的决定权在Bob手上,所以当n>2的情况下Bob总能构造两条对称链,这样无论Alice怎样拿Bob都在对称链上拿相同的即可。)

#include<iostream> 
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
#define LL long long 
#define INF 0x1f1f1f1f
using namespace std;


int main()
{
    freopen("xx.in","r",stdin);
    freopen("xx.out","w",stdout);

    int n;
    while(cin >> n && n!=0)
    {
        if(n == 1 || n == 2) cout << "Alice"<< endl;
        else cout << "Bob" << endl;
    }

    return 0;   
}
19851月至200512月,原油现货交易价格如下。数据为:26.41 26.73 28.29 27.63 27.84 26.87 27.12 28.08 29.08 30.38 29.75 26.3 18.83 13.26 10.42 13.34 14.3 12.78 11.15 15.9 14.77 15.27 15 17.94 18.75 16.6 18.83 18.73 19.38 20.29 21.37 19.73 19.59 19.96 18.51 16.7 16.94 16.01 17.08 17.99 17.51 15.16 16.31 15.18 13.37 13.58 15.32 17.24 17.03 18.15 20.19 20.42 19.9 20.27 18.31 18.83 20.13 19.94 19.89 21.82 22.68 21.54 20.28 18.54 17.4 17.07 20.69 27.32 39.51 35.23 28.85 28.44 21.54 19.16 19.63 20.96 21.13 20.56 21.68 22.26 22.23 23.37 21.48 19.12 18.9 18.68 19.44 20.85 22.11 21.6 21.87 21.48 21.71 20.62 19.89 19.5 20.26 20.6 20.44 20.53 20.02 18.85 17.88 18.29 18.79 16.92 15.43 14.17 15.19 14.48 14.79 16.9 18.31 19.37 20.3 17.56 18.39 18.19 18.05 17.76 18.39 18.49 19.17 20.38 18.89 17.4 17.56 17.84 17.54 17.64 18.18 19.55 17.74 19.54 21.47 21.2 19.76 20.92 20.42 22.25 24.38 23.35 23.75 25.92 24.15 20.3 20.41 20.21 20.88 19.8 20.14 19.61 21.18 21.08 19.15 17.64 17.21 15.44 15.61 15.39 13.95 14.18 14.3 13.34 16.14 14.42 11.22 11.28 12.75 12.27 16.16 18.23 16.84 18.37 20.53 21.9 24.51 21.75 24.59 25.6 28.27 30.43 27.31 25.74 29.01 32.5 27.43 33.12 30.84 33.48 33.82 27.8 28.66 27.39 27.09 27.86 28.37 28.2 26.1 27.2 23.36 21.07 19.37 19.84 19.2 21.48 26.12 27.36 25.02 26.8 27.21 28.99 30.52 26.86 26.79 30.45 33.56 37.05 31.02 26.13 29.32 30.06 30.61 31.78 28.89 28.77 29.95 32.89 33.26 35.56 36.13 37.74 39.41 35.76 43.5 41.8 49.55 51.49 49.98 42.76 47.1 51.93 55.07 50.41 51.48 56.84 60.34 69.31 66.37 60.6 56.41 59.88 请回答:(1)研究1985-2005原油现货价格的走势,对原油价格拟合 ARIMA模型。(2)研究原油现货价格的波动特征。如果存在条件异异方差,则拟合适当的条件异方差模型。 (3)预测2006-2007月原油现货价格的走势及 95%的置信区间。
06-04
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值