宏定义(下面部分用旧版本):
#define rep(i,l,r) for(int i=(l),_=(r);i<=_;i++)
#define per(i,r,l) for(int i=(r),_=(l);i>=_;i--)
#define MS(arr,x) memset(arr,x,sizeof(arr))
#define INE(i,u) for(int i=head[u];~i;i=e[i].next)
#define LL long long
01背包:25s
for(int i=1;i<=n;i++)
for(int j=0;j<=v;j++)
{
opt[i][j]=opt[i-1][j];
if(j-v[i]>0) opt[i][j]=max(opt[i-1][j],opt[i-1][j-c[i]]+w[i]);
}
for(int i=1;i<=n;i++)
for(int j=v;j>=0;j--)
if(j-c[i]>=0) opt[j]=max(opt[j],opt[j-c[i]]+w[i]);
完全背包:15s
rep(i,1,n) rep(j,w[i],m)
opt[j]=max(opt[j],opt[j-w[i]]+q[i]);
LIS:40s
下降:两个>改成< 不降:两个>改成>=
for(int i=1;i<=n;i++)
{
if(a[i]>b[cnt]) b[++cnt]=a[i];
else
{
l=0,r=cnt;
while(l<r)
{
mid=(l+r)>>1;
if(a[i]>b[mid]) l=mid+1;
else r=mid;
}
b[l]=a[i];
}
}
归并&逆序对:60s
void merge_sort(int l,int r)
{
if(l>=r)return;
int mid=(l+r)>>1;
int p=l,q=mid+1,i=l;
merge_sort(l,mid);
merge_sort(mid+1,r);
while(p<=mid||q<=r)
{
if(q>r||(p<=mid&&a[p]<a[q]))
t[i++]=a[p++];
else
{
t[i++]=a[q++];
cnt+=mid-p+1;
}
}
rep(i,l,r) a[i]=t[i];
}
快速幂:25s
现在熟练了,以后就一行了
怕a*a或者t*a爆了的话见下面的
LL pow_mod(LL a,LL b,LL p){LL t=1;for(;b;b>>=1,a=a*a%p)if(b&1)t=t*a%p;return t;}
(快速乘):
这个也升级啦,尽量把小的放前面
ll mul(ll a,ll b,ll p){ll t=0;for(;b;b>>=1,a=(a<<1)%p)if(b&1)t=(t+a)%p;return t;}
扩展欧几里得:30s
神奇的代码缩减
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b) return x=1,y=0,a;
LL d=exgcd(b,a%b,x,y);
return swap(x,y),y-=a/b*x,d;
}
floyd+最小环:40s
rep(k,1,n)
{
rep(i,1,k-1) rep(j,i+1,k-1)
ans=min(ans,dis[i][j]+map[i][k]+map[k][j]);
rep(i,1,n) rep(j,1,n)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
Phi:
LL phi(LL n)
{
LL res=n;
LL sqn=(LL)sqrt(n+0.5);
for(LL i=2;i<=sqn;i==2?i++:i+=2) if(n%i==0)
{
res=res/i*(i-1);
while(n%i==0)n/=i;
}
if(n>1)res=res/n*(n-1);
return res;
}
线性筛素数&欧拉&莫比乌斯:100s
void get_prim_phi_mu()
{
cnt=0; MS(flag,0); phi[1]=1; mu[1]=1;
rep(i,2,n)
{
if(!flag[i])
prim[++cnt]=i,phi[i]=i-1,mu[i]=-1;
for(int j=1;j<=cnt && i*prim[j]<=n;j++)
{
flag[i*prim[j]]=1;
if(i%prim[j]==0)
{
phi[i*prim[j]]=phi[i]*prim[j];
mu[i*prim[j]]=0;
break;
}
else
{
phi[i*prim[j]]=phi[i]*(prim[j]-1);
mu[i*prim[j]]=-mu[i];
}
}
}
}
bsgs:学了再放
输入数据
inline const int read()
{
int r=0,k=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-')k=-1;
for(;c>='0'&&c<='9';c=getchar())r=r*10+c-'0';
return k*r;
}
组合数取模:30s
MS(C,0);
rep(i,0,n) C[i][0]=1;
rep(i,1,n) rep(j,1,i)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
求一个的话需要逆元:40s
inline LL C(int n,int m)
{
if(m+m>n) m=n-m;
LL s1=1,s2=1;
rep(i,1,m) s1=(s1*(n-i+1))%mod,
s2=(s2*i)*mod;
return (s1*pow_mod(s2,mod-2,mod))%mod;
}
如果范围较小而p较大,可以预处理阶乘、阶乘逆元
据说逆元用pow_mod会被卡,特意收集了VFK的模板
inline int modinv(const int &a)
{
int x1 = 1, x2 = 0, x3 = Mod;
int y1 = 0, y2 = 1, y3 = a;
while (y3 != 1)
{
int k = x3 / y3;
x1 -= y1 * k, x2 -= y2 * k, x3 -= y3 * k;
swap(x1, y1), swap(x2, y2), swap(x3, y3);
}
return y2 >= 0 ? y2 : y2 + Mod;
}
KMP:
rep(i,2,n)
{
while(j&&s[i]!=s[j+1]) j=next[j];
next[i]=j+=s[i]==s[j+1];
}
EXKMP:
int t=0; ext[1]=n;
rep(i,2,n)
{
ext[i]=max(0,min(ext[i-t+1],t+ext[t]-i));
while(s[ext[i]+1] == s[i+ext[i]]) ext[i]++;
if(i+ext[i] > t+ext[t]) t=i;
}