重走长征路---OI每周刷题记录---8月30日 2014

总目录详见https://blog.csdn.net/mrcrack/article/details/84471041

做题原则,找不到测评地址的题不做。2018-11-28

重走长征路---OI每周刷题记录---8月30日  2014

本周共计26题+2题

测评地址:

方差线段树:

1.「ch52」还教室

暴力:

2.「FJ2014集训」圈地(50分)

随机旋转坐标系+计算几何:

3.「FJ2014集训」圈地

dp:

4.「cf459E」Pashmak and Graph

随机旋转坐标系:

5.平面上的最接近点对

模拟:

6.「cf460A」Vasya and Socks

暴力:

7.「cf460B」Little Dima and Equation  

8.「bzoj3031」理科男

二分+贪心:

9.「cf460C」Present

环形均分纸牌:

10.「bzoj3032」七夕祭

dfs+欧拉图:

11.「bzoj3033」太鼓达人

爬山:

12.「bzoj3680」吊打XXX   //在线测评地址https://www.luogu.org/problemnew/show/P1337

13.「FJ互测」油滴扩展·改

vector+(set)

14.「bzoj3224」JoyOI 1728 普通平衡树

线段树:

15.「bzoj2212」[Poi2011]Tree Rotations

lucas定理:

16.「bzoj2982」combination   //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=2982

   27.【模板】卢卡斯定理   //在线测评地址https://www.luogu.org/problemnew/show/P3807

   28.【模板】扩展卢卡斯   //在线测评地址https://www.luogu.org/problemnew/show/P4720

最小割:

17.「bzoj1324」Exca王者之剑

离线+线段树合并:

18.「bzoj3545」[ONTAK2010]Peaks

贪心:

19.「cf461A」Appleman and Toastman

树形dp:

20.「cf461B」Appleman and Tree

dfs:

21.「bzoj1751」[Usaco2005 qua]Lake Counting

dp+概率:

22.「JoyOI1864」[Poetize I]守卫者的挑战

骗分:

23.「bzoj1865」 [Poetize I]终极武器(50分)

dijkstra:

24.「bzoj1752」[Usaco2005 qua]Til the Cows Come Home

dfs序+主席树+kruskal:

25.「bzoj3551」[ONTAK2010]Peaks加强版

map+线段树:

26.「泉七培训-刘定峰」花园
 

题解:

方差线段树:

1.「ch52」还教室

暴力:

2.「FJ2014集训」圈地(50分)

随机旋转坐标系+计算几何:

3.「FJ2014集训」圈地

dp:

4.「cf459E」Pashmak and Graph

随机旋转坐标系:

5.平面上的最接近点对

模拟:

6.「cf460A」Vasya and Socks

暴力:

7.「cf460B」Little Dima and Equation  

8.「bzoj3031」理科男

二分+贪心:

9.「cf460C」Present

环形均分纸牌:

10.「bzoj3032」七夕祭

dfs+欧拉图:

11.「bzoj3033」太鼓达人

爬山:

12.「bzoj3680」吊打XXX 

//P1337 [JSOI2004]平衡点 / 吊打XXX
//在线测评地址https://www.luogu.org/problemnew/show/P1337
//看了https://www.cnblogs.com/DukeLv/p/9495789.html基本确定二分套二分+正交分解,测试点3WA,89分,已经到头
//https://www.luogu.org/discuss/show/67504联想到里面的讨论,三分套三分,才有写感觉
//有一个疑问,二分都能用三分处理吗?先想想.2019-2-22 18:02
//单调增,能用三分吗?单调减,能用三分吗?
//可能是开口向上的抛物线,也可能是开口向下的抛物线,能用三分吗?
//先提出问题,若开始摸索,要花很长时间.
//决定,采用2种方法,一是模拟退火算法,二是网络中流行的正解.先AC了该题,经验丰富了,再解决上述问题.2019-2-22 19:10
//考虑了分母不能为0的二分套二分+正交分解,测试点3WA,89分,代码如下.2019-2-24 14:32
//加上n==1的特判,估计测试数据里没有.所以再次提交,还是,测试点3WA,89分
//结果呢,竟然AC了,非上述所想,测试点3竟然是特判,不可思议.
//类测试点3的数据提供给大家
//输入
//1
//-1 9 3
//输出
//-1.000 9.000
//以下为正解AC代码,正交分解+二分套二分.思路纯正.2019-2-24 15:55
#include <stdio.h>
#include <math.h>
#define maxn 1010
int n;
double x[maxn],y[maxn],w[maxn],xs=99999,xe=-99999,ys=99999,ye=-99999,x_now,y_now;//xs x坐标的最小值,xe x坐标的最大值
double ans_x,ans_y;
double min(double a,double b){
    return a<b?a:b;
}
double max(double a,double b){
    return a>b?a:b;
}
double x_judge(double x0,double y0){
    int i;
    double L,ans_x=0;
    for(i=1;i<=n;i++){
        L=sqrt((x[i]-x0)*(x[i]-x0)+(y[i]-y0)*(y[i]-y0));
        if(L<=0.00001)continue;//漏了此处判定,分母不能为0
        ans_x+=w[i]*(x[i]-x0)/L;//向右为正
    }
    return ans_x;
}
double y_judge(double y0){
    int i;
    double x_left,x_right,x_mid,ans_y=0,L;
    x_left=xs,x_right=xe;
    while(x_left+0.00001<x_right){
        x_mid=(x_left+x_right)/2;
        if(x_judge(x_mid,y0)>=0)x_left=x_mid;
        else x_right=x_mid;//此处写成else x_left=x_mid;,笔误,跟踪代码后,才发现
    }
    for(i=1;i<=n;i++){
        L=sqrt((x[i]-x_left)*(x[i]-x_left)+(y[i]-y0)*(y[i]-y0));
        if(L<=0.00001)continue;//漏了此处判定,分母不能为0
        ans_y+=w[i]*(y[i]-y0)/L;
    }
    x_now=x_left;
    return ans_y;
}
void bisection(){//二分套二分
    double y_left,y_right,y_mid;
    y_left=ys,y_right=ye;
    while(y_left+0.00001<y_right){
        y_mid=(y_left+y_right)/2;
        if(y_judge(y_mid)>=0)y_left=y_mid;//此处写成y_right=y_mid;,跟踪代码后,才查出//向上为正
        else y_right=y_mid;
    }
    y_now=y_left;
}
int main(){
    int i;
    scanf("%d",&n);
    for(i=1;i<=n;i++)scanf("%lf%lf%lf",&x[i],&y[i],&w[i]),xs=min(xs,x[i]),xe=max(xe,x[i]),ys=min(ys,y[i]),ye=max(ye,y[i]);
    if(n==1){//漏了特判,现在加上
        printf("%.3lf %.3lf\n",x[1],y[1]);
        return 0;
    }
    bisection();
    printf("%.3lf %.3lf\n",x_now,y_now);
    return 0;
}

//P1337 [JSOI2004]平衡点 / 吊打XXX
//在线测评地址https://www.luogu.org/problemnew/show/P1337
//看了https://www.cnblogs.com/DukeLv/p/9495789.html基本确定二分套二分+正交分解,测试点3WA,89分,已经到头
//https://www.luogu.org/discuss/show/67504联想到里面的讨论,三分套三分,才有写感觉
//有一个疑问,二分都能用三分处理吗?先想想.2019-2-22 18:02
//单调增,能用三分吗?单调减,能用三分吗?
//可能是开口向上的抛物线,也可能是开口向下的抛物线,能用三分吗?
//先提出问题,若开始摸索,要花很长时间.
//决定,采用2种方法,一是模拟退火算法,二是网络中流行的正解.先AC了该题,经验丰富了,再解决上述问题.2019-2-22 19:10
//模拟退火,比较偏爱此文代码https://www.cnblogs.com/BearChild/p/6536030.html
//无论怎么看代码,都觉得有些地方处理得不好,那么,开始自己的编写.
//sqrt((10000-(-10000))^2+(10000-(-10000))^2)*1000*1000=2.83*10000*1000*1000=2.83*10^10
//故最小值的设置,要大于2.83*10^10,初始化最小值为1e12
//喜欢此文变量的写法https://www.cnblogs.com/JoeFan/p/4341029.html
//return rand()%1000000/1000000.0;//此处写成return rand()%1000000/1000000;
//查了会.
//srand(20191231);提交67分,测试点5,6,8WA.
//srand(804589);提交89分,测试点8WA.
//调了
//return rand()%10000/10000.0;//此处写成return rand()%1000000/1000000.0;
//SA(100000);//此处写成SA(1000000);
//T*=0.97;//此处写成T*=0.98;
//才AC. 2019-2-23   23:01
//模拟退火算法,要拿满分很难,但拿70%的分数,概率还是比较大的.
//一下为模拟退火算法AC代码.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define maxn 1100
double w[maxn],minw=0;
struct mass_point{
    double x,y;
}a[maxn],ans,now,next;
int n;
double Rand(){
    return rand()%10000/10000.0;//此处写成return rand()%1000000/1000000.0;//此处写成return rand()%1000000/1000000;
}
double dis(mass_point a,mass_point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));//此处写成return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
double judge(mass_point b){
    double ret=0;
    int i;
    for(i=1;i<=n;i++)ret+=w[i]*dis(a[i],b);
    if(ret<minw)minw=ret,ans=b;
    return ret;
}
void SA(double T){
    int i;
    double dE;
    now=ans;
    while(T>0.001){
        next.x=now.x+(Rand()*2-1)*T;//此处写成next.x+=now.x+(rand()*2-RAND_MAX)*T;昏招
        next.y=now.y+(Rand()*2-1)*T;//此处写成next.y+=now.y+(rand()*2-RAND_MAX)*T;昏招
        dE=judge(now)-judge(next);
        if(dE>0||exp(dE/T)>Rand())now=next;
        T*=0.97;//此处写成T*=0.98;
    }
    for(i=1;i<=1000;i++){
        next.x=ans.x+(Rand()*2-1)*T;//此处写成next.x=now.x+(rand()*2-RAND_MAX)*T;
        next.y=ans.y+(Rand()*2-1)*T;//此处写成next.y=now.y+(rand()*2-RAND_MAX)*T;
        judge(next);
    }
}
int main(){
    int i;
    srand(20191231);
    ans.x=0,ans.y=0;
    scanf("%d",&n);
    for(i=1;i<=n;i++)scanf("%lf%lf%lf",&a[i].x,&a[i].y,&w[i]),ans.x+=a[i].x,ans.y+=a[i].y;
    ans.x/=n,ans.y/=n,minw=judge(ans);
    SA(100000);//此处写成SA(1000000);
    printf("%.3lf %.3lf\n",ans.x,ans.y);
    return 0;
}

//P1337 [JSOI2004]平衡点 / 吊打XXX
//在线测评地址https://www.luogu.org/problemnew/show/P1337
//看了https://www.cnblogs.com/DukeLv/p/9495789.html基本确定二分套二分+正交分解,测试点3WA,89分,已经到头
//https://www.luogu.org/discuss/show/67504联想到里面的讨论,三分套三分,才有写感觉
//有一个疑问,二分都能用三分处理吗?先想想.2019-2-22 18:02
//单调增,能用三分吗?单调减,能用三分吗?
//可能是开口向上的抛物线,也可能是开口向下的抛物线,能用三分吗?
//先提出问题,若开始摸索,要花很长时间.
//决定,采用2种方法,一是模拟退火算法,二是网络中流行的正解.先AC了该题,经验丰富了,再解决上述问题.2019-2-22 19:10
//考虑了分母不能为0的二分套二分+正交分解,测试点3WA,89分,代码如下.2019-2-24 14:32
#include <stdio.h>
#include <math.h>
#define maxn 1010
int n;
double x[maxn],y[maxn],w[maxn],xs=99999,xe=-99999,ys=99999,ye=-99999,x_now,y_now;//xs x坐标的最小值,xe x坐标的最大值
double ans_x,ans_y;
double min(double a,double b){
    return a<b?a:b;
}
double max(double a,double b){
    return a>b?a:b;
}
double x_judge(double x0,double y0){
    int i;
    double L,ans_x=0;
    for(i=1;i<=n;i++){
        L=sqrt((x[i]-x0)*(x[i]-x0)+(y[i]-y0)*(y[i]-y0));
        if(L<=0.00001)continue;//漏了此处判定,分母不能为0
        ans_x+=w[i]*(x[i]-x0)/L;//向右为正
    }
    return ans_x;
}
double y_judge(double y0){
    int i;
    double x_left,x_right,x_mid,ans_y=0,L;
    x_left=xs,x_right=xe;
    while(x_left+0.00001<x_right){
        x_mid=(x_left+x_right)/2;
        if(x_judge(x_mid,y0)>=0)x_left=x_mid;
        else x_right=x_mid;//此处写成else x_left=x_mid;,笔误,跟踪代码后,才发现
    }
    for(i=1;i<=n;i++){
        L=sqrt((x[i]-x_left)*(x[i]-x_left)+(y[i]-y0)*(y[i]-y0));
        if(L<=0.00001)continue;//漏了此处判定,分母不能为0
        ans_y+=w[i]*(y[i]-y0)/L;
    }
    x_now=x_left;
    return ans_y;
}
void bisection(){//二分套二分
    double y_left,y_right,y_mid;
    y_left=ys,y_right=ye;
    while(y_left+0.00001<y_right){
        y_mid=(y_left+y_right)/2;
        if(y_judge(y_mid)>=0)y_left=y_mid;//此处写成y_right=y_mid;,跟踪代码后,才查出//向上为正
        else y_right=y_mid;
    }
    y_now=y_left;
}
int main(){
    int i;
    scanf("%d",&n);
    for(i=1;i<=n;i++)scanf("%lf%lf%lf",&x[i],&y[i],&w[i]),xs=min(xs,x[i]),xe=max(xe,x[i]),ys=min(ys,y[i]),ye=max(ye,y[i]);
    bisection();
    printf("%.3lf %.3lf\n",x_now,y_now);
    return 0;
}

//P1337 [JSOI2004]平衡点 / 吊打XXX
//在线测评地址https://www.luogu.org/problemnew/show/P1337
//为了演练 模拟退火 算法,找到该题
//因自带版本支持luogu不利,在noi linux下装了firefox,费了好大劲,该系统还要慢慢熟悉
//研究了题目,发现考的是物理,考物理的重心。已经考到了物理竞赛的层面。
//用重心公式计算样例,发现输出不对。
//仔细想了想,该题考的是物体平衡问题。
//n个力处理的最好方式,是正交分解,计算合力是否为0
//计算合力,编写一个函数。
//x,y两个坐标进行枚举
//最好的方式,还是x进行二分,对应每个x值,y再进行二分。
//二分套二分
//此句描述多余,假设绳子是完全弹性的(不会造成能量损失)
//20000^2+20000^2=8*10^8 1000*8*10^8=8*10^11 int容易溢出 采用 long long
//想不到,long long采用%d方式输出,在linux编译,会出现警告,真是太好了。
//二分有些想法,分错了方向,笔误不断,跟踪是个好办法,问题一个一个找到,排除
//样例通过,提交89分。测试点3 WA。凭借深厚的物理功底,该题得分比较满意。2019-2-22
//以下为89分代码,思路 正交分解+二分套二分
#include <stdio.h>
#include <math.h>
#define maxn 1010
int n;
double x[maxn],y[maxn],w[maxn],xs=99999,xe=-99999,ys=99999,ye=-99999,x_now,y_now;//xs x坐标的最小值,xe x坐标的最大值
double ans_x,ans_y;
double min(double a,double b){
    return a<b?a:b;
}
double max(double a,double b){
    return a>b?a:b;
}
double x_judge(double x0,double y0){
    int i;
    double L,ans_x=0;
    for(i=1;i<=n;i++)L=sqrt((x[i]-x0)*(x[i]-x0)+(y[i]-y0)*(y[i]-y0)),ans_x+=w[i]*(x[i]-x0)/L;//向右为正
    return ans_x;
}
double y_judge(double y0){
    int i;
    double x_left,x_right,x_mid,ans_y=0,L;
    x_left=xs,x_right=xe;
    while(x_left+0.00001<x_right){
        x_mid=(x_left+x_right)/2;
        if(x_judge(x_mid,y0)>=0)x_left=x_mid;
        else x_right=x_mid;//此处写成else x_left=x_mid;,笔误,跟踪代码后,才发现
    }
    for(i=1;i<=n;i++)L=sqrt((x[i]-x_left)*(x[i]-x_left)+(y[i]-y0)*(y[i]-y0)),ans_y+=w[i]*(y[i]-y0)/L;
    x_now=x_left;
    return ans_y;
}
void bisection(){//二分套二分
    double y_left,y_right,y_mid;
    y_left=ys,y_right=ye;
    while(y_left+0.00001<y_right){
        y_mid=(y_left+y_right)/2;
        if(y_judge(y_mid)>=0)y_left=y_mid;//此处写成y_right=y_mid;,跟踪代码后,才查出//向上为正
        else y_right=y_mid;
    }
    y_now=y_left;
}
int main(){
    int i;
    scanf("%d",&n);
    for(i=1;i<=n;i++)scanf("%lf%lf%lf",&x[i],&y[i],&w[i]),xs=min(xs,x[i]),xe=max(xe,x[i]),ys=min(ys,y[i]),ye=max(ye,y[i]);
    bisection();
    printf("%.3lf %.3lf\n",x_now,y_now);
    return 0;
}

13.「FJ互测」油滴扩展·改

vector+(set)

14.「bzoj3224」JoyOI 1728 普通平衡树

线段树:

15.「bzoj2212」[Poi2011]Tree Rotations

lucas定理:

16.「bzoj2982」combination

//2982: combination
//在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=2982
//没想到,直接注册,该题,即可提交,进行测评,太高兴了.等到需要权限帐号时再说.
//样例很快模拟成功,看了数据范围,只靠乘法逆元是肯定不行的,采用Lucas定理.
//https://www.cnblogs.com/fzl194/p/9095177.html喜欢此文Lucas定理的介绍.
//因1<=m<=n<=200,000,000,一个不当心就要int溢出
//采用long long
//在编写过程中,学会了linux下,中英文切换。收获挺大。2019-2-25
//样例通过,提交Wrong_Answer,不敢相信
//排查了代码,确有失误
//return (C(n%mod,m%mod)*Lucas(n/mod,m/mod))%mod;//此处写成return C(n%mod,m%mod)*Lucas(n/mod,m/mod);
//发现上述问题,修改,提交AC。2019-2-25
//该题,还可改进,预先算出1-10007之间的阶乘,
//样例通过,提交AC,运行时间,只有之前的十分之一,效果太明显了,以下为优化过的代码。2019-2-25
#include <stdio.h>
#define LL long long
#define mod 10007
LL fact[10010];
LL quick_pow(LL a,LL n){
    LL ans=1;
    while(n){
        if(n&1)ans=(ans*a)%mod;
        a=(a*a)%mod;
        n>>=1;
    }
    return ans;
}
LL C(LL n,LL m){
    LL i,a,b;
    if(n<m)return 0;
    a=fact[n],b=(fact[m]*fact[n-m])%mod;
    return (a*quick_pow(b,mod-2))%mod;
}
LL Lucas(LL n,LL m){
    if(m==0)return 1;
    return (C(n%mod,m%mod)*Lucas(n/mod,m/mod))%mod;//此处写成return C(n%mod,m%mod)*Lucas(n/mod,m/mod);
}
void init(){
    LL i;
    fact[0]=1;
    for(i=1;i<=mod;i++)fact[i]=(fact[i-1]*i)%mod;
}https://www.lydsy.com/JudgeOnline/status.php?user_id=mrwalking
int main(){
    int t;
    LL n,m;
    init();
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld",&n,&m);
        printf("%lld\n",Lucas(n,m));
    }
    return 0;
}

//2982: combination
//在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=2982
//没想到,直接注册,该题,即可提交,进行测评,太高兴了.等到需要权限帐号时再说.
//样例很快模拟成功,看了数据范围,只靠乘法逆元是肯定不行的,采用Lucas定理.
//https://www.cnblogs.com/fzl194/p/9095177.html喜欢此文Lucas定理的介绍.
//因1<=m<=n<=200,000,000,一个不当心就要int溢出
//采用long long
//在编写过程中,学会了linux下,中英文切换。收获挺大。2019-2-25
//样例通过,提交Wrong_Answer,不敢相信
//排查了代码,确有失误
//return (C(n%mod,m%mod)*Lucas(n/mod,m/mod))%mod;//此处写成return C(n%mod,m%mod)*Lucas(n/mod,m/mod);
//发现上述问题,修改,提交AC。2019-2-25
#include <stdio.h>
#define LL long long
#define mod 10007
LL quick_pow(LL a,LL n){
    LL ans=1;
    while(n){
        if(n&1)ans=(ans*a)%mod;
        a=(a*a)%mod;
        n>>=1;
    }
    return ans;
}
LL C(LL n,LL m){
    LL i,a=1,b=1;
    if(n<m)return 0;
    for(i=n;i>=n-m+1;i--)a=(a*i)%mod;//此处写成for(i=n;i>=n-m+1;i++)a=(a*i)%mod;//此处写成for(i=1;i<=n-m+1;i++)a=(a*i)%mod;
    for(i=1;i<=m;i++)b=(b*i)%mod;
    return (a*quick_pow(b,mod-2))%mod;
}
LL Lucas(LL n,LL m){
    if(m==0)return 1;
    return (C(n%mod,m%mod)*Lucas(n/mod,m/mod))%mod;//此处写成return C(n%mod,m%mod)*Lucas(n/mod,m/mod);
}
int main(){
    int t;
    LL n,m;
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld",&n,&m);
        printf("%lld\n",Lucas(n,m));
    }
    return 0;
}

   27.【模板】卢卡斯定理

//P3807 【模板】卢卡斯定理
//在线测评地址https://www.luogu.org/problemnew/show/P3807
//int此题容易溢出,long long比较保险
//样例通过,提交AC。2019-2-25
#include <stdio.h>
#define LL long long
LL quick_pow(LL a,LL n,LL p){
    LL ans=1;
    while(n){
        if(n&1)ans=(ans*a)%p;
        a=(a*a)%p;
        n>>=1;
    }
    return ans;
}
LL C(LL n,LL m,LL p){
    LL i,a=1,b=1;
    if(n<m)return 0;
    for(i=n;i>=n-m+1;i--)a=(a*i)%p;
    for(i=1;i<=m;i++)b=(b*i)%p;
    return (a*quick_pow(b,p-2,p))%p;
}
LL Lucas(LL n,LL m,LL p){
    if(m==0)return 1;
    return (C(n%p,m%p,p)*Lucas(n/p,m/p,p))%p;
}
int main(){
    LL t,n,m,p;
    scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld%lld",&n,&m,&p);
        n=n+m;
        printf("%lld\n",Lucas(n,m,p));
    }
    return 0;
}

   28.【模板】扩展卢卡斯

//P4720 【模板】扩展卢卡斯
//在线测评地址https://www.luogu.org/problemnew/show/P4720
//比较偏爱此文关于拓展卢卡斯lucas定理的介绍https://blog.csdn.net/qq_40679299/article/details/80495032
//采用long long,但还担心溢出
//编写过程中,有些笔误,通过编译代码的过程,一一排除
//测试样例过程中,输出一直报 段错误,在linux下,怎么回事.
//发现此文https://blog.csdn.net/Rainloving/article/details/45575769段错误一般发生在极端情况的未考虑
//果然,if(n<m)return 0;//漏了此行
//if(n==0)return 1;//漏了此行
//修改,段错误,消除
//测试样例数据,输出结果,没对上
//排查,发现for(i=1;i<=n%pk;i++)//此处写成for(i=1;i<n%pk;i++) 跟踪了代码才发现
//样例1通过,样例2,输出结果,没对上
//测试的过程中,遇到了 浮点数例外,linux下,一查
//if(p>1)cnt++,a[cnt]=C(n,m,p,p),b[cnt]=p;//测试中,误删了b[cnt]=p,造成了CRT()中,分母出现0的情况//p是质数
//浮点数例外 排除
//LL ans=1,i;//此处写成LL ans,i;   ans忘记初始化,默认为0,这个问题,查了30分钟.
//一个初始化过程,查了这么久,样例1,样例2通过,
//还有一个担心,计算过程中,有没有可能long long溢出,不过,还不打算用快速乘,先做到这个份上.
//提交AC.高兴啊,耗费2天时间,时间主要花在,原理,推导上.2019-2-28 21:50
//会做一两个省选题,没什么了不起,会做100个,那么,基本跨入大牛行列.
//还有一个要说明,没有很长一段时间linux下编程经验,不要轻易在考试中进行linux编程,如遇到  段错误  浮点数例外 等,就会手忙脚乱.2019-2-28 21:55
#include <stdio.h>
#define LL long long
LL n,m,p,a[1000],b[1000],cnt=0;
LL exgcd(LL a,LL b,LL *x,LL *y){//拓展欧几里得算法
    LL d,t;
    if(b==0){
        *x=1,*y=0;
        return a;
    }
    d=exgcd(b,a%b,x,y);
    t=*x,*x=*y,*y=t-a/b**y;
    return d;
}
LL quick_pow(LL a,LL b,LL pk){//快速幂
    LL ans=1;
    while(b){
        if(b&1)ans=(ans*a)%pk;
        a=(a*a)%pk;
        b>>=1;
    }
    return ans;
}
LL inv(LL a,LL pk){//求逆元
    LL x,y;
    exgcd(a,pk,&x,&y);
    x=(x%pk+pk)%pk;
    return x;
}
LL fact(LL n,LL p,LL pk){//排列数
    LL ans=1,i;//此处写成LL ans,i;   ans忘记初始化,默认为0,这个问题,查了30分钟.
    if(n==0)return 1;//漏了此行
    for(i=1;i<pk;i++)
        if(i%p) ans=(ans*i)%pk;
    ans=quick_pow(ans,n/pk,pk);
    for(i=1;i<=n%pk;i++)//此处写成for(i=1;i<n%pk;i++) 跟踪了代码才发现
        if(i%p)ans=(ans*i)%pk;
    ans=ans*fact(n/p,p,pk)%pk;
    return ans;
}
LL C(LL n,LL m,LL p,LL pk){//组合数
    LL f1,f2,f3,k=0,i,ans;
    if(n<m)return 0;//漏了此行
    f1=fact(n,p,pk),f2=fact(m,p,pk),f3=fact(n-m,p,pk);
    for(i=n;i;i/=p)k+=i/p;
    for(i=m;i;i/=p)k-=i/p;
    for(i=n-m;i;i/=p)k-=i/p;
    ans=f1*inv(f2,pk)%pk*inv(f3,pk)%pk*quick_pow(p,k,pk)%pk;
    return ans;
}
LL CRT(){//中国剩余定理
    LL LCM=1,i,ans=0,x,y;
    for(i=1;i<=cnt;i++)LCM*=b[i];
    for(i=1;i<=cnt;i++){
        exgcd(LCM/b[i],b[i],&x,&y);
        x=(x%b[i]+b[i])%b[i];
        ans=(ans+a[i]*x*LCM/b[i])%LCM;
    }
    return ans;
}
LL exlucas(LL n,LL m,LL p){//拓展卢卡斯定理
    LL t,i,q=p;
    for(i=2;p>1&&i*i<=q;i++){
        t=1;
        while(p%i==0){
            p/=i,t*=i;
        }
        if(t>1)cnt++,a[cnt]=C(n,m,i,t),b[cnt]=t;
    }
    if(p>1)cnt++,a[cnt]=C(n,m,p,p),b[cnt]=p;//测试中,误删了b[cnt]=p,造成了CRT()中,分母出现0的情况//p是质数
    return CRT();
}
int main(){
    scanf("%lld%lld%lld",&n,&m,&p);
    printf("%lld\n",exlucas(n,m,p));
    return 0;
}

最小割:

17.「bzoj1324」Exca王者之剑

离线+线段树合并:

18.「bzoj3545」[ONTAK2010]Peaks

贪心:

19.「cf461A」Appleman and Toastman

树形dp:

20.「cf461B」Appleman and Tree

dfs:

21.「bzoj1751」[Usaco2005 qua]Lake Counting

dp+概率:

22.「JoyOI1864」[Poetize I]守卫者的挑战

骗分:

23.「bzoj1865」 [Poetize I]终极武器(50分)

dijkstra:

24.「bzoj1752」[Usaco2005 qua]Til the Cows Come Home

dfs序+主席树+kruskal:

25.「bzoj3551」[ONTAK2010]Peaks加强版

map+线段树:

26.「泉七培训-刘定峰」花园

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值