总目录详见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.「泉七培训-刘定峰」花园