标签:卡特兰数 sed while att 排序 取数 辗转相除法 iostream noip
当b为偶数:ab=ab/2 * ab/2
当b为奇数:ab=ab/2 * ab/2 * a
核心代码:
ll quickpow(ll a,ll b) { ll ret=1; while(b) { if(b%2==1) ret=ret*a%P; a=a*a%P; b/=2; } return ret; }
题目号 | 题目名 | 注释 |
洛谷P1965 | 【NOIP2013TG】转圈游戏 | 简单推导公式 |
洛谷P3197 |
【HNOI2008】越狱 |
与组合数学结合+容斥 |
#include<iostream> using namespace std; #define maxn 10000001 int prime[maxn],v[maxn],f[maxn];//prime为素数表 //v为每个数的最小质因子 //f数组判断是否是素数 int n,m,k; void primes(int n) { k=0; for(int i=2;i<=n;i++)//从2开始 { if(v[i]==0) { v[i]=i;//i是质数,则i的最小质因子为本身 prime[++k]=i; f[i]=1; } for(int j=1;j<=k;j++) { if(prime[j]>v[i]||prime[j]*i>n) break; //如果i有比prime[j]更小的质因子 //或者超出n的范围 v[i*prime[j]]=prime[j];//prime[j]是合数i*prime[j]的最小质因子 } } } int main() { cin>>n>>m; primes(n); for(int i=1;i<=m;i++) { int x; cin>>x; if(f[x]==1) cout<<"Yes"<<endl; else cout<<"No"<<endl; } }
题目号 | 题目名 | 注释 |
洛谷P3383 | 线性筛素数 | 模板题 |
洛谷P2926 | 【USACO08DEC】Patting Heads | 特殊筛法 |
Codeforces 776B | Sherlock and his girlfriend | 特判+筛法 |
void divide(int x) { m=0; for(int i=2;i*i<=n;i++)//一个数至多只有一个大于根号n的质因子 //所以后面特判 前面只要到根号n { if(n%i==0)//i是质数 { p[++m]=i; c[m]=0; } while(n%i==0) { n=n/i;//除掉所有的i c[m]++; //i的指数加1 } } if(n>1)//特判大于根号n的那个 { p[++m]=n; c[m]=1; } }
题目号 | 题目名 | 注释 |
洛谷P1075 | 【NOIP2012PJ】质因数分解 | 模板题 |
洛谷P1463 | 【HAOI2007】反素数 | 搜索+约数个数 |
辗转相除法求gcd
int gcd(int a,int b) { if(b==0) return a; else return gcd(b,a%b); }
求lcm:
a*b=gcd(a,b)*lcm(a,b)
题目号 | 题目名 | 注释 |
洛谷P1072 | 【NOIP2009TG】Hankson的趣味题 | 推导 |
void exgcd(int a,int b,int &d,int &x,int &y) { int t; if(b==0)//当b=0时 gcd(a,b)=a //因为1*a+0*0=a 所以ax+by=gcd(a,b)有一组解为 //x=1 y=0 { d=a; x=1; y=0; } else { exgcd(b,a%b,d,x,y); t=x;//推导得公式 x=y; y=t-(a/b)*y; } }
题目号 | 题目名 | 注释 |
洛谷P1516 | 青蛙的约会 | 简单推导公式 |
洛谷P1082 | 【NOIP2012TG】同余方程 | 模板题 |
洛谷P2421 | 【NOI2002】荒岛野人 | 推导公式+条件判断 |
对于a/b mod p(b和p互质)
First 费马小定理:
如果b和p互质 则bp≡b(mod p)
由此可得bp-1≡1(mod p) 结合求逆元方程b*x≡1(mod p) 得到bp-1≡b*x(mod p)
所以x≡bp-2(mod p)结合快速幂求出x
#include<cstdio> #define ll long long using namespace std; int n,p; inline ll ksm(ll a,ll b){ ll ans=1; a%=p; while(b){ if(b&1) ans=ans*a%p; a=a*a%p; b>>=1; } return ans%p; } void write(ll x){ if(x<0) putchar(‘-‘),x=-x; if(x>9) write(x/10);putchar(x%10^48); } int main(){ scanf("%d%d",&n,&p); for(int i=1;i<=n;i++) write(ksm(i,p-2)),putchar(‘\n‘); return 0; }
Second 解不定方程
解a*x≡1(mod p)等于解ax+py=1
因为p是质数 所以gcd(a,p)=1;
即解ax+py=gcd(a,p) 用exgcd解x
#include<cstdio> using namespace std; int x,y; void exgcd(int a,int b){ if(!b){x=1,y=0;return ;} exgcd(b,a%b); int t=x; x=y,y=t-a/b*y; } void write(int x){ if(x>9) write(x/10); putchar(x%10^48); } int main(){ int n,p; scanf("%d%d",&n,&p); for(int i=1;i<=n;++i) exgcd(i,p),write((x%p+p)%p),putchar(‘\n‘); return 0; }
Third 线性递推
#include<cstdio> #define ll long long using namespace std; const int maxn=3e6+5; ll inv[maxn]={0,1}; int main(){ int n,p; scanf("%d%d",&n,&p); printf("1\n"); for(int i=2;i<=n;i++) inv[i]=(ll)p-(p/i)*inv[p%i]%p,printf("%d\n",inv[i]); return 0; }
题目号 | 题目名 | 注释 |
POJ1845 | Sumdiv | 约数和+模板 |
对于多个x≡ai(mod mi)
M=∏ni=1mi Mi=M/mi
ti是线性同余方程Mi*ti≡1(mod mi)的一个解
x=∑ni=1ai*Mi*ti
int intchina(int n) { int Mi,x,y,d,ans=0; M=1; for(int i=1;i<=n;i++) M*=m[i]; for(int i=1;i<=n;i++) { Mi=M/m[i]; exgcd(Mi,m[i],d,x,y); ans=(ans+Mi*x*a[i])%M; } return (ans+M)%M; }
题目号 | 题目名 | 注释 |
洛谷P1495 | 曹冲养猪 | 模板题 |
UVA756 | Biorhythms | 模板+特殊解 |
#include<iostream> #include<cstdio> using namespace std; #define LL long long LL T,n,m,p; LL quickpow(LL a,LL b) { LL ret=1; while(b) { if(b&1) ret=ret*a%p; a=a*a%p; b>>=1; } return ret; } LL C(LL n,LL m) { if(m>n) return 0; LL a=1,b=1; for(LL i=n-m+1;i<=n;i++) a=a*i%p;//计算n!/(n-m)! for(LL i=2;i<=m;i++) b=b*i%p;//计算1/m! return a*quickpow(b,p-2)%p;//费马小定理求逆元 } LL Lucas(LL n,LL m) { if(!m) return 1; else return (C(n%p,m%p)*Lucas(n/p,m/p))%p;//递推公式 } int main() { scanf("%lld",&T); while(T) { T--; scanf("%lld%lld%lld",&n,&m,&p); printf("%lld\n",Lucas(n,m)); } }
题目号 | 题目名 | 注释 |
洛谷P3807 | 卢卡斯定理 | 模板题 |
组合:A(n,m)=n(n-1)*(n-2)*……*(n-m+1)= n!/(n-m)!
排列:C(n,m)=A(n,m)/m!=n!/(m!(n-m)!)
题目名 | 题目号 | 注释 |
洛谷P1066 | 【NOIP2006TG】2^k进制数 | 复杂高精+组合推导(有点难) |
洛谷P2822 | 【NOIP2016TG】组合数问题 | 二维前缀和+杨辉三角 |
洛谷P1350 | 车的放置 | 推导矩阵公式 |
洛谷P3166 | 【CQOI2004】数三角形 | 组合+GCD |
洛谷P2532 | 【AHOI2012】树屋阶梯 | 卡特兰数+高精 |
洛谷P3200 | 【HNOI2009】有趣的数列 | 卡特兰数+质因数分解 |
洛谷P1375 | 小猫 | 卡特兰数+逆元 |
枚举所有在i与j之间的k
把一段区间分成两段为两个状态
如果是环形可以考虑断环成链 开数组2n
初始化 f[i][i]=1或者权值
答案要枚举所有的左端点到后n位
核心代码:
f1[i][j]=max(f1[i][j],f1[i][k]+f1[k+1][j]+sum[j]-sum[i-1]); f2[i][j]=min(f2[i][j],f2[i][k]+f2[k+1][j]+sum[j]-sum[i-1]);
题目号 | 题目名 | 注释 |
洛谷P1880 | 【NOI1995】石子合并 | 断链成环 |
洛谷P1063 | 能量项链 | 中等难度 |
洛谷P2426 | 删数 | 从两边删除区间 |
洛谷P3146 | 【USACO160PEN】248 | 类似2048游戏 |
洛谷P1005 | 【NOIP2007TG】矩阵取数游戏 | 高精+翻倍 |
洛谷P3205 | 【HNOI2010】合唱队 | 用两个数组 |
#include<iostream> using namespace std; int father[5001]; int n,m,p; int find(int x) { if(father[x]!=x)//路径压缩优化 father[x]=find(father[x]);//把路上的所有点祖先全部改掉 return father[x]; } void unionn(int x,int y) { father[y]=x;//y的祖先为x的祖先 //相当于合并祖先 } int main() { cin>>n>>m>>p; for(int i=1;i<=n;i++) { father[i]=i;//所有数据初始祖先为自己 //独立的一个数为一个集合 } for(int i=1;i<=m;i++) { int x,y; cin>>x>>y; int r1,r2; r1=find(x); r2=find(y);//寻找两个数的祖先 if(r1!=r2)//如果不是同一个祖先 { unionn(r1,r2);//合并 } } for(int i=1;i<=p;i++) { int x,y; cin>>x>>y; if(find(x)==find(y))//如果是同一个祖先 { cout<<"Yes"<<endl;//是 } else cout<<"No"<<endl;//否 } }
题目号 | 题目名 | 注释 |
洛谷P3367 | 【模板】并查集 | 如题 |
洛谷P2024 |
【NOI2001】食物链 |
搞好三者关系 |
洛谷P1525 |
关押罪犯 |
排序+并查集 |
洛谷P1111 |
修复公路 |
eazy |
洛谷P1197 |
【JSOI2008】星球大战 |
逆向思维 |
Kruskal
#include<iostream> #include<algorithm> using namespace std; struct edge { int l,r,w;//左端点 右端点 权值 }e[200001]; int father[5001]; int n,m,k=0,tot; bool cmp(const edge &a,const edge &b)//用权值排序 { if (a.w<b.w) return 1; else return 0; } int find(int x) { if(father[x]!=x) father[x]=find(father[x]); return father[x]; } void unionn(int x,int y) { int fa=find(x); int fb=find(y); if(fa!=fb) father[fa]=fb; } int main() { cin>>n>>m; for(int i=1;i<=n;i++) father[i]=i; for(int i=1;i<=m;i++) { cin>>e[i].l>>e[i].r>>e[i].w; } sort(e+1,e+1+m,cmp); for(int i=1;i<=m;i++) { if(find(e[i].l)!=find(e[i].r)) { unionn(e[i].l,e[i].r); tot+=e[i].w; k++; } if(k==n-1) break;//到n-1条时退出 } cout<<tot; }
题目号 | 题目名 | 注释 |
洛谷P3366 | 【模板】最小生成树 | 如题 |
洛谷P1195 | 口袋的天空 | 处理边的关系 |
洛谷P2330 | 【SCOI2005】繁忙的都市 | 记下最大值 |
Tarjan
void Tarjan(int u) { dfn[u]=low[u]=++num; st[++top]=u;//入栈 vis[u]=1;//判断是否在栈中 for(int i=h[u];i;i=e[i].next) { int v=e[i].to; if(!dfn[v]) { Tarjan(v); low[u]=min(low[u],low[v]);//low表示u与其子孙到达的最小编号 } else if(vis[v])//判断v是否在栈中 low[u]=min(low[u],dfn[v]); //可以改成 min(low[u],low[v]) //因为此时v的low和dfn还未修改 } if(dfn[u]==low[u]) { co[u]=++col;//属于第col个强连通分量 while(st[top]!=u) { co[st[top]]=col; vis[st[top--]]=0; } --top; } }
题目号 | 题目名 | 注释 |
洛谷P2341 | [HAOI2006]受欢迎的牛 | 缩点+小思想 |
标签:卡特兰数 sed while att 排序 取数 辗转相除法 iostream noip
原文地址:https://www.cnblogs.com/BrokenString/p/9462209.html