@Angela-Balzac
2018-01-16T04:04:04.000000Z
字数 7133
阅读 1312
By Angela Balzac in 2018
若p是质数,a是任意整数,并且a不能被p整除,于是:
OEIS A000010
φ(n)表示1~n以内和n互质的数的个数。
p表示n的所有质因数。
有
线性筛欧拉函数
int m[maxn],phi[maxn],p[maxn],pt;//m[i]是i的最小素因数,p是素数,pt是素数个数
int get_phi(){
phi[1]=1;
int N=maxn,k;
for(int i=2;i<N;i++){
if(!m[i]){//i是素数
p[pt++]=m[i]=i,phi[i]=i-1;
}
for(int j=0;j<pt&&(k=p[j]*i)<N;j++){
m[k]=p[j];
if(m[i]==p[j]){//为了保证以后的数不被再筛,要break
phi[k]=phi[i]*p[j];
/*这里的phi[k]与phi[i]后面的∏(p[i]-1)/p[i]都一样(m[i]==p[j])只差一个p[j],就可以保证∏(p[i]-1)/p[i]前面也一样了*/
break;
}
else{
phi[k]=phi[i]*(p[j]-1);//积性函数性质
}
}
}
}
若,则:
更常用的:
定义:设m>1,,使得成立的最小的r,称为a对模m的阶,记为。
数m有原根的充要条件: (p为奇素数,k为任意正整数)。
定理
找原根
若欲求m的原根的话,对进行质因数分解,求出所有质因子,若对于任意,均满足,则g是m的原根。
求原根的代码
#include<bits/stdc++.h>
using namespace std;
int p[100007], c;
long long pow_mod(long long a,long long x,long long m){
long long ans=1;
while(x){
if(x&1){
ans=ans*a%m;
}
a=a*a%m;
x>>=1;
}
return ans;
}
bool ok(int x,int ph,int m){
for(int i=0;i<c;i++){
if(pow_mod(x,ph/p[i],m)==1){
return 0;
}
}
return 1;
}
void divide(int x){
c=0;
for(int i=2;i*i<=x;i++){
if(x%i==0){
p[c++]=i;
while(x%i==0){
x/=i;
}
}
}
if(x>1){
p[c++]=x;
}
}
int main(){
int wxh;
scanf("%d",&wxh);
while(wxh--){
int n;
scanf("%d",&n);
int m=n,ans=m;
for(int i=2;i*i<=n;i++){
if(n%i==0){
ans=ans/i*(i-1);
while(n%i==0){
n/=i;
}
}
}
if(n>1){
ans=ans/n*(n-1);
}
divide(ans);
int x=ans;
while(!ok(x,ans,m)){
x--;
}
printf("%d\n",x);
}
return 0;
}
当存在某个x,式子成立时,称“d是模p的二次剩余”。
当对任意x不成立时,称“d是模p的二次非剩余”。
学不来
关于如何计算二次剩余,详见Miskcoo的博客
由费马小定理:
根据欧拉准则,二次剩余有解当且仅当
如果c满足不是p的二次剩余,那么是方程的解。因为有一半的数是非二次剩余,所以可以随机c,验证即可。
详见Philipsweng的博客
使用Baby-step giant-step算法
(临时)详见Yuiffy的博客
模板(Poj 2417)
#include<bits/stdc++.h>
using namespace std;
long long p,b,n;
void exgcd(long long c,long long d,long long &x,long long &y){
if(!d){
x=1;y=0;
return ;
}
exgcd(d,c%d,x,y);
long long z=y,r=x-(c/d)*y;
x=z;y=r;
}
void work(){
long long m=(long long)sqrt(p),bb=1,nn=n,inv,t;
map<int,int> num;
map<int,bool> app;
app[1]=1;
num[1]=0;
for(int i=1;i<=m-1;i++){
bb=bb*b%p;
if(!app[bb]){
app[bb]=1;
num[bb]=i;
}
}
bb=bb*b%p;
exgcd(bb,p,inv,t);
if(inv>0){
inv%=p;
}
else{
inv=inv%p+p;
}
for(int i=0;i<=m;i++){
if(app[nn]){
printf("%lld\n",i*m+num[nn]);
return;
}
nn=nn*inv%p;
}
printf("no solution\n");
}
int main(){
while(~scanf("%lld%lld%lld",&p,&b,&n)){
work();
}
return 0;
}
存在一个p,使得对p个点的完全图红蓝染色,要么存在n个点的红色完全子图,要么存在m个点的蓝色完全子图。
把最小的p记作R(n,m),称为Ramsey数,一般用到R(3,3)=6。
更大的Ramsey数特别难算。
OEIS A008275(有符号)
表示将n个不同元素构成m个圆排列的方案数。
通俗来说,就是n个不同人围m个相同圆桌而坐,要求各桌非空,其不同方案数。
第一类Stirling数又分为无符号()与有符号()两种。
递推式
性质
-
-
-
-
-
-
-
-
递推式
性质
例子
有n个仓库,每个仓库有两把钥匙,共2n把钥匙。同时又有n位官员。问如何放置钥匙使得所有官员都能够打开所有仓库?(只考虑钥匙怎么放到仓库中,而不考虑官员拿哪把钥匙。)那如果官员分成m个不同的部,部中的官员数量和管理的仓库数量一致。那么有多少方案使得,同部的所有官员可以打开所有本部管理的仓库,而无法打开其他部管理的仓库?(同样只考虑钥匙的放置。)
第一问很经典,就是打开将钥匙放入仓库构成一个环:1号仓库放2号钥匙,2号仓库放3号钥匙……n号仓库放1号钥匙。这种情况相当于钥匙和仓库编号构成一个圆排列方案数是种。
而第二问就对应的将n个元素分成m个圆排列,方案数就是第一类无符号Stirling数 。如要要考虑官员的情况,只需再乘上即可。
OEIS A008277
表示将n个不同的元素拆分成m个集合的方案数。
通俗来说,就是将n个不同的球放入m个无差别的盒子中,要求盒子非空,求方案数。
公式
递推式
性质
OEIS A000108
应用
代码A(Luogu 1375)
#include<bits/stdc++.h>
#define mo 1000000007
using namespace std;
const int N=2e5+5;
long long ans;
int n;
long long ksm(long long x,long long y){
long long ans=1;
for(;y;y>>=1,x=x*x%mo){
if(y&1){
ans=ans*x%mo;
}
}
return ans;
}
long long C(int n,int m){
long long ans=1;
for(int i=1;i<=m;i++,n--){
ans=ans*n%mo*ksm(i,mo-2)%mo;
}
return ans;
}
int main(){
scanf("%d",&n);
ans=C(2*n,n)-C(2*n,n-1);
printf("%lld",(ans+mo)%mo);
}
代码B(Luogu 1722)
#include<bits/stdc++.h>
using namespace std;
int h[110];
int main(){
int n,i,j;
h[0]=1;
scanf("%d",&n);
for(i=1;i<=n;++i){
for(j=0;j<i;++j){
h[i]=(h[i]+h[j]*h[i-1-j])%100;
}
}
printf("%d\n",h[n]);
return 0;
}
OEIS A001006
一个给定的数n的默慈金数是在一个圆上的n个点间,画出彼此不相交弦的全部方法的总数。
例子
1.在一个网格上,若限定每步只能向右移动一格,可以右上,右下,横向,向右,并禁止移动到y=0以下的地方,则以这种走法移动n步从(0,0)到(0,n)的可能形成的路径的总数为n的默慈金数。
2.有一个1*n的矩阵,固定第一个数为1,其他填正整数,且相邻数的差不能超过1,求方案数。
代码
void get_motzkin(){
long long x,y;
m[1]=1,m[2]=2;
for(int i=3;i<maxx;i++){
exgcd(i+2,mod,x,y);
x=(x%mod+mod)%mod;
m[i]=(((2*i+1)*m[i-1])%mod+((3*i-3)*m[i-2])%mod)*x;
m[i]=(m[i]%mod+mod)%mod;
}
}
OEIS A001263
例子
在由n对"("和")"组成的字符串中,共有k对"("与")"相邻,这样的字符串一共有N(n,k)个。
OEIS A000110
例子
划分一个集合的方案数。
代码
#include<bits/stdc++.h>
using namespace std;
long long S(long long m,long long n){//第二类Stirling数
if(m==1||m==n){
return 1;
}
else{
return S(m-1,n-1)+S(m,n-1)*m;
}
}
int main(){
long long n,sum=0;
n=read();
for(long long i=1;i<=n;i++){
sum+=S(i,n);
}
printf("%d",sum);
return 0;
}
OEIS A011971
OEIS A027641
递推式
性质
例子
计算
(Zoj 2865,代码如下)
#include<bits/stdc++.h>
#define mod 1000000007
#define maxx 2018
using namespace std;
long long c[maxx][maxx];//组合数
long long b[maxx];//伯努利数
long long inv[maxx];//逆元
long long tmp[maxx];
long long n;
inline long long read(){
long long X=0,w=1;
char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
return X*w;
}
void init(){
for(int i=0;i<maxx;i++){
c[i][0]=c[i][i]=1;
if(i==0){
continue;
}
for(int j=1;j<i;j++){
c[i][j]=(c[i-1][j]%mod+c[i-1][j-1]%mod)%mod;
}
}
inv[1]=1;
for(int i=2;i<maxx;i++){
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}
b[0]=1;
for(int i=1;i<maxx;i++){
long long ans=0;
if(i==maxx-1){
break;
}
for(int j=0;j<i;j++){
ans+=c[i+1][j]*b[j];
ans%=mod;
}
ans*=-inv[i+1];
ans=(ans%mod+mod)%mod;
b[i]=ans;
}
}
long long work(int k){
long long ans=inv[k+1],sum=0;
for(int i=1;i<=k+1;i++){
sum+=c[k+1][i]*tmp[i]%mod*b[k+1-i]%mod;
sum%=mod;
}
ans*=sum;
ans%=mod;
return ans;
}
int main(){
init();
long long wxh=read();
while(wxh--){
n=read()%mod;
int k=read();
tmp[0]=1;
for(int i=1;i<maxx;i++){
tmp[i]=tmp[i-1]*(n+1)%mod;
}
printf("%lld\n", work(k));
}
return 0;
}
不可用
不可用
OEIS A000326
定理
OEIS A001318
不可用
不可用
转载请表明出处,谢谢。