NOIP板子
FIRST lucas(卢卡斯)
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int T,n,m,p;
long long a[100005],b[100005];
long long lucas(int x,int y)
{
if(x<y) return 0;
else if(x<p) return b[x]*a[y]*a[x-y]%p;
else return lucas(x/p,y/p)*lucas(x%p,y%p)%p;
}
int main()
{
scanf("%d",&T);
a[0]=a[1]=b[0]=b[1]=1;
while(T--)
{
scanf("%d%d%d",&n,&m,&p);
for(int i=2;i<=n+m;i++) b[i]=b[i-1]*i%p;//阶乘
for(int i=2;i<=n+m;i++) a[i]=(p-p/i)*a[p%i]%p;//线性求逆元
for(int i=2;i<=n+m;i++) a[i]=a[i-1]*a[i]%p;//逆元的前缀积
printf("%lld\n",lucas(n+m,m));
}
return 0;
}
SECOND fast_pow(快速幂)
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
ll a,b,mod;
ll pow(ll x,ll y)
{
int a=1;x%=mod;
a%=mod; //注意1 0 1这组数据
while(y)
{
if(y%2)a*=x;
x*=x;
x%=mod;a%=mod;
y>>=1; }
return a;
}
int main()
{
cin>>a>>b>>mod;
cout<<a<<"^"<<b<<" mod "<<mod<<"="<<pow(a,b);
}
THIRD Matrix fast power
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
ll n,k,mod=1e9+7;//开long long
struct AC
{
ll data[101][101];
}a,f;
AC work(AC x ,AC y)
{
AC c;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
c.data[i][j]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
c.data[i][j]=c.data[i][j]%mod+x.data[i][k]*y.data[k][j]%mod;
return c;
}
AC fast_pow(AC x,ll mi)
{
AC ans=f;
while(mi)
{
if(mi&1)ans=work(ans,x);
x=work(x,x);
mi>>=1;
}
return ans;
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a.data[i][j];
for(int i=1;i<=n;i++)f.data[i][i]=1;
AC x=fast_pow(a,k);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cout<<x.data[i][j]%mod<<" ";//注意取模
cout<<"\n";
}
}
FOURTH Pei Shu theorem (裴蜀定理)
#include<iostream>
#include<cstdio>
using namespace std;
int n,x,y;
int gcd(int xx,int yx)
{
xx=xx<0?(-xx):xx;
yx=yx<0?(-yx):yx;
if(yx==0)return xx;
return gcd(yx,xx%yx);
}
int main()
{
cin>>n;cin>>x>>y;
y=gcd(x,y);
for(int i=3;i<=n&&y!=1;i++)
cin>>x,y=gcd(y,x);
cout<<y;
}
FIFTH 匈牙利算法
//二分图最大匹配
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,e,edge[2010][1010],u,v,vis[2010],p[2010],ans;
bool DFS(int x)
{
for(int j=1;j<=edge[x][0];j++)
if(!vis[edge[x][j]])
{
vis[edge[x][j]]=1;
if(!p[edge[x][j]]||DFS(p[edge[x][j]]))
{p[edge[x][j]]=x;return 1;}
}
return 0;
}
int main()
{
cin>>n>>m>>e;
for(int i=1;i<=e;i++)
{
cin>>u>>v;
if(u>n||v>m)continue;
edge[u][++edge[u][0]]=n+v;
edge[n+v][++edge[n+v][0]]=u;
}
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(DFS(i))ans++;
}
/*for(int i=1;i<=m;i++)
if(p[i+n])ans++;*/
cout<<ans;
}
SIXTH 逆元
//线性求逆元
#include<iostream>
#define ll long long
using namespace std;
int inv[3000010],n,p;
int main()
{
cin>>n>>p;
inv[1]=1;
for(int i=2;i<=n;i++)
inv[i]=(ll)(p-p/i)*inv[p%i]%p;//开long long
for(int i=1;i<=n;i++)
cout<<inv[i]<<"\n";
}
//扩欧求逆元
#include<iostream>
using namespace std;
int n,mod,x,y;
void exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1,y=0;return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
return ;
}
int main()
{
cin>>n>>mod;
exgcd(n,mod,x,y);
cout<<(x+mod)%mod;
}
SEVENTH 线性基
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
int n;ll x,ans,mp[55];
void add(ll xx)
{
for(int i=50;i>=0;i--)
if(xx&(1ll<<i))
{
if(!mp[i])
{mp[i]=xx;break;}
xx^=mp[i];
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>x,add(x);
ll ret=0;
for(int i=50;i>=0;i--)
if ((ret^mp[i])>ret)
ret^=mp[i];
cout<<ret;
}
EIGHTH 逆序对
//树状数组求逆序对
#include<algorithm>
#include<cstdio>
#include<map>
#include<iostream>
#define ll long long
using namespace std;
const ll N=2000000;
ll n,f[N],tree[N],flag;
string ch;
map<string,int>mp;
ll lowbit(ll x)
{
return x&(-x);
}
void add(ll x)
{
while(x<=n)
tree[x]++,x+=lowbit(x);
}
ll sum(ll x)
{
ll s=0;
while(x>0)
s+=tree[x],x-=lowbit(x);
return s;
}
struct AC
{
ll id,size;
}dd[N];
bool cmp(AC x,AC y)
{
return x.size<y.size;
}
void work()
{
sort(dd+1,dd+1+n,cmp);
f[dd[1].id]=1;
for(ll i=2;i<=n;i++)
{
if(dd[i].size==dd[i-1].size) f[dd[i].id]=f[dd[i-1].id];
else f[dd[i].id]=f[dd[i-1].id]+1;
}
}
int main()
{
ll ans=0;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
cin>>ch,mp[ch]=flag++;
for(int i=1;i<=n;i++)
cin>>ch,dd[i].size=mp[ch],dd[i].id=i;
work();
add(f[n]);
for(ll i=n-1;i>0;i--)
{
ans+=sum(f[i]-1);
add(f[i]);
}
printf("%lld",ans);
return 0;
}
#include<bits/stdc++.h>
using namespace std;
//下面就是 归并排序求逆序对 的过程==
const int maxn=1008611;
int a[maxn],r[maxn],ans=0,n;//ans作为全局变量,记录逆序对的数量;
void msort(int s,int t)
{
if(s==t) return ;
int mid=(s+t)/2;
msort(s,mid);//→→→→→→→递归的体现
msort(mid+1,t);//→→→→→↗↗
int i=s,j=mid+1,k=s;
while(i<=mid&&j<=t){
if(a[i]<=a[j])
r[k]=a[i],k++,i++;
else{
r[k]=a[j],k++,j++;
ans+=mid-i+1;//只可意会,不可言传==;
}
}
while(i<=mid)
r[k]=a[i],k++,i++;
while(j<=t)
r[k]=a[j],k++,j++;
for(int i=s;i<=t;i++)
a[i]=r[i];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
msort(1,n);//从1到n将a数组排序;
printf("%d\n",ans);
return 0;
}
NINETH splay
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
const int N=1e5+5;
int fa[N],size[N],key[N],cnt[N],ch[N][2],sz,root;
inline int read()//读入优化
{
int ans=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
return ans*f;
}
inline void update(int x)//更新节点的值
{
size[x]=cnt[x]+size[ch[x][0]]+size[ch[x][1]];
}
inline int get(int x)//查询x是左节点还是右节点
{
return x==ch[fa[x]][1];
}
inline void clear(int x)//清空x的值
{
ch[x][0]=ch[x][1]=fa[x]=size[x]=cnt[x]=key[x]=0;
}
inline void rotate(int x,int &k)//只是将x旋到了其父亲的位置
{
int old,oldfa,o;
old=fa[x];oldfa=fa[old];o=get(x);
//x要与其父亲节点交换位置 即将x旋到其父亲的位置
if(old==k)k=x;//k就是x的父亲节点 经过处理后x会来到k的位置完成操作
else ch[oldfa][get(old)]=x;//更新其经过操作的父亲的节点
//因为k是跟节点 所以当k是x的父亲 x经过操作就是根节点 不用更新其父亲的节点
fa[x]=oldfa;//更新x的父亲
ch[old][o]=ch[x][o^1];//更新原来父亲的节点
fa[ch[x][o^1]]=old;//更新原来节点的父亲
ch[x][o^1]=old;//更新自己的节点
fa[old]=x;//更新原来父亲的父亲
update(x),update(old);//更新两个被修改的节点的size值
}
inline void splay(int x,int &k)//将x旋到k的位置
{
while(x!=k)//操作边界
{
if(fa[x]!=k)rotate(get(x)^get(fa[x])?x:fa[x],k);
//如果x当前的父亲不是k 若是x与其父亲节点都是左或右节点 可以将x的父亲向上旋
rotate(x,k);//将x向上旋
}
}
inline void insert(int x)//插入x
{
if(!root){root=++sz;size[sz]=cnt[sz]=1;key[sz]=x;return;}
//还没有建成树
int now=root,o;
while(1)
{
if(x==key[now])//x的值与当前节点的值相同
{
++cnt[now];//计数器++
splay(now,root);//将当前节点旋到根位置 以便
update(now);//更新当前节点的size
return;
}
o=x>key[now]?1:0;//判断x应是左还是右节点
if(!ch[now][o])//如果此位置没有节点
{
ch[now][o]=++sz;//更新节点的size
size[sz]=cnt[sz]=1;//更新size和计数器
key[sz]=x;fa[sz]=now;//初始化新节点
splay(sz,root);//将此节点旋到根节点
return;
}
else now=ch[now][o];//继续向下寻找
}
}
inline int find_pos(int x)//寻找x的位置
{
int now=root;
while(1)//根据二叉平衡树的性质
{
if(x==key[now]){return now;}
if(x<key[now])now=ch[now][0];
else now=ch[now][1];
}
}
inline int pre()//前驱
{
int now=ch[root][0];//从左子树中找
while(ch[now][1])now=ch[now][1];//一直向右子节点找 直到不存在右子节点
return now;
}
inline int nex()//后继
{
int now=ch[root][1];//从右子树找
while(ch[now][0])now=ch[now][0];//一直向左子节点找 直到不存在左子节点
return now;
}
void del(int x)//删点
{
splay(find_pos(x),root);//现将此点旋到根
if(cnt[root]>1){--cnt[root];return;}//若是有多个值相同的 计数器--
if(!ch[root][0]&&!ch[root][1]){clear(root);root=0;return;}//若是只有一个值 一个节点 清空树即可
if(ch[root][0]&&ch[root][1])//左子树 右子树都存在
{
int oldroot=root;//记录当前的根
splay(pre(),root);//将前驱旋成根
fa[ch[oldroot][1]]=root;//把原先根的右子树连到新根上
ch[root][1]=ch[oldroot][1];
clear(oldroot);//清空原先的根
update(root);//更新现在的根
}
else//存在一颗子树
{
int o=ch[root][1]>0;
root=ch[root][o];//更新根
clear(fa[root]);//清空原根
fa[root]=0;//更新
}
}
inline int find_order_of_key(int x)//寻找x的排名
{
int res=0,now=root;
while(1)//根据二叉平衡树的性质
{
if(x<key[now])now=ch[now][0];
else
{
res+=size[ch[now][0]];
if(x==key[now]){splay(now,root);return res+1;}
res+=cnt[now];
now=ch[now][1];
}
}
}
inline int find_by_order(int x)//寻找排名为x的数
{
int now=root;
while(1)//根据二叉平衡树的性质
{
if(x<=size[ch[now][0]])now=ch[now][0];
else
{
int temp=size[ch[now][0]]+cnt[now];
if(x<=temp)return key[now];
else{x-=temp;now=ch[now][1];}
}
}
}
int main()
{
int T=read();//数据组数
int opt,x;//opt表示操作类型 x为操作的数
while(T--)
{
opt=read();x=read();//读入数据
if(opt==1)insert(x);//插入
else if(opt==2)del(x);//删除
else if(opt==3)printf("%d\n",find_order_of_key(x));//查询x的排名
else if(opt==4)printf("%d\n",find_by_order(x));//查询排名为x的数
else if(opt==5)//先插入成根 查询前驱 删除
{insert(x); printf("%d\n",key[pre()]);del(x);}
else if(opt==6)//先插入成根 查询后继 删除
{insert(x);printf("%d\n",key[nex()]);del(x);}
}
return 0;
}
TENTH 筛素数
//线性筛
#include<iostream>
using namespace std;
int tot=0,p[10000001],c[10000001],n,m;
int sushu(int x)
{
for(int i=2;i<=x;i++)
{
if(p[i]!=1)
c[tot++]=i;
for(int j=0;j<tot;j++)
{
if(i*c[j]>x)
break;
p[i*c[j]]=1;
if(i%c[j]==0)
break;
}
}
}
int main()
{
cin>>n>>m;
sushu(n);
for(int i=1;i<=m;i++)
{
cin>>n;
if(n==1)
{
cout<<"No"<<endl;
continue;
}
if(p[n])
cout<<"No"<<endl;
else cout<<"Yes"<<endl;
}
}
ELEVENTH hash(哈希)
//双hash值 输出多少不同的字符串
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<set>
using namespace std;
typedef unsigned long long ull;
ull hh=19260817;
int base=131;
ull hhh=19660813;
struct AC
{
int x,y;
}a[10010];
char ch[10010];
int n;
ull len;
int ans=1;
bool cmp(AC x,AC y)
{
return x.x<y.x;
}
ull hash1(char s[])
{
int len=strlen(s);
ull ans=0;
for (int i=0;i<len;i++)
ans=(ans*base+(ull)s[i])%hh;
return ans;
}
ull hash2(char s[])
{
int len=strlen(s);
ull ans=0;
for (int i=0;i<len;i++)
ans=(ans*base+(ull)s[i])%hhh;
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",ch);
a[i].x=hash1(ch);
a[i].y=hash2(ch);
}
sort(a+1,a+n+1,cmp);
for (int i=2;i<=n;i++)
if (a[i].x!=a[i-1].x||a[i].y!=a[i-1].y)
ans++;
printf("%d\n",ans);
}
TWELVETH 一笔画(欧拉回路)
图是联通的 .统计所有的点的出度。如果出度全部为偶数或者恰好只有两个点为奇数。则可以一笔画。
联通的话用并查集也可以。用dfs从任意一个点进行搜索然后看下能不能走到所有的点。也可以。但是推荐用dfs,因为可以一边统计出度信息。
THIRTEENTH LCA
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,root,p,next[1000010],last[500010],h[1000010];
int per[500010][20],log[500010],dep[500010],x,y;
inline int read()
{
char ch=getchar();int xv=0;
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')xv=xv*10+ch-'0',ch=getchar();
return xv;
}
void add(int x,int y)
{
p++;next[p]=last[x];
last[x]=p;h[p]=y;
swap(x,y);
p++;next[p]=last[x];
last[x]=p;h[p]=y;
}
void dfs(int x,int fa)
{
for(int i=last[x];i;i=next[i])
if(h[i]!=fa)dep[h[i]]=dep[x]+1,per[h[i]][0]=x,dfs(h[i],x);
}
int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
while(dep[x]>dep[y])
x=per[x][log[dep[x]-dep[y]]-1];
if(x==y)return x;
for(int i=log[dep[x]]-1;i>=0;i--)
if(per[x][i]!=per[y][i])
x=per[x][i],y=per[y][i];
return per[x][0];
}
int main()
{
//cin>>n>>m>>root;
n=read();m=read(),root=read();
for(int i=1;i<n;i++)
x=read(),y=read(),add(x,y);
dep[root]=1;per[root][0]=root;
dfs(root,0);
for(int i=1;i<=n;i++)
log[i]=log[i-1]+(1<<log[i-1]==i);
for(int i=1;i<=19;i++)
for(int j=1;j<=n;j++)
per[j][i]=per[per[j][i-1]][i-1];
for(int i=1;i<=m;i++)
x=read(),y=read(),cout<<lca(x,y)<<"\n";
}
FOURTEENTH Tarjan+拓扑
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=100010;
int p,next[maxn],last[maxn],h[maxn],dfn[maxn],low[maxn],tot,flag;
int stack[maxn],data[maxn],data_level[maxn],fa[maxn],vis[maxn];
int n,m,x[maxn],y[maxn],l[maxn],hh[maxn],nxt[maxn],pp,per[maxn];
int ans[maxn],ansx,ru[maxn];
queue<int>q;
inline int read()
{
char ch=getchar();int xv=0;
while(ch<'0'||ch>'9')ch=getchar();
while(ch<='9'&&ch>='0')xv=xv*10+ch-'0',ch=getchar();
return xv;
}
void add(int u,int v)
{
p++;next[p]=last[u];
last[u]=p;h[p]=v;
}
void tarjan(int x)
{
int ansz=0;
dfn[x]=low[x]=++tot;
vis[x]=1;stack[++flag]=x;
for(int i=last[x];i;i=next[i])
{
if(!dfn[h[i]])
tarjan(h[i]),low[x]=min(low[x],low[h[i]]);
else if(vis[h[i]])
low[x]=min(low[x],low[h[i]]);
}
if(low[x]==dfn[x])
{
do{
fa[stack[flag]]=x;
ansz+=data[stack[flag]];
vis[stack[flag]]=0;
flag--;
}while(x!=stack[flag+1]);
ans[x]=data_level[x]=ansz;per[++per[0]]=x;
}
}
void add_level(int u,int v)
{
pp++;nxt[pp]=l[u];
l[u]=pp;hh[pp]=v;
ru[v]++;
}
void build()
{
for(int i=1;i<=m;i++)
if(fa[x[i]]!=fa[y[i]])
add_level(fa[x[i]],fa[y[i]]);
}
void TP()
{
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=l[x];i;i=nxt[i])
{
ru[hh[i]]--;
if(ru[hh[i]]==0)q.push(hh[i]);
ans[hh[i]]=max(ans[hh[i]],data_level[hh[i]]+ans[x]);
ansx=max(ansx,ans[hh[i]]);
}
ansx=max(ansx,ans[x]);
}
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)data[i]=read();
for(int i=1;i<=m;i++)x[i]=read(),y[i]=read(),add(x[i],y[i]);
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
build();
for(int i=1;i<=per[0];i++)
if(ru[per[i]]==0)q.push(per[i]);
TP();
cout<<ansx;
}
FIFTEENTH 单源最短路
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
int x,y,z,n,m,k,last[100010],nxt[200010],h[200010],wis[200010],dis[100010],p,vis[100010];
void add(int u,int v,int w)
{
p++;nxt[p]=last[u];
last[u]=p;h[p]=v;
wis[p]=w;
}
priority_queue< pair<int,int> >q;
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=m;i++)
cin>>x>>y>>z,add(x,y,z);
memset(dis,127/2,sizeof(dis));
dis[k]=0;q.push(make_pair(0,k));
while(!q.empty())
{
x=q.top().second,q.pop();
if(vis[x])continue;vis[x]=1;
for(int i=last[x];i;i=nxt[i])
{
if(dis[h[i]]>dis[x]+wis[i])
{
dis[h[i]]=dis[x]+wis[i];
q.push(make_pair(-dis[h[i]],h[i]));
}
}
}
for(int i=1;i<=n;i++)cout<<dis[i]<<" ";
return 0;
}
//热浪 双向路
#include<iostream>
#include<queue>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
queue<int>q;
int p,n,m,s,t,vis[2501],last[2501],wis[12401],nxt[12401],h[12401],x,y,z,dis[2501];
void add(int u,int v,int w)
{
p++;nxt[p]=last[u];
h[p]=v;wis[p]=w;last[u]=p;
swap(u,v);
p++;nxt[p]=last[u];
h[p]=v;wis[p]=w;last[u]=p;
}
int main()
{
cin>>n>>m>>s>>t;
for(int i=1;i<=m;i++)
cin>>x>>y>>z,add(x,y,z);
memset(dis,127/2,sizeof(dis));dis[s]=0;
q.push(s);vis[s]=1;
while(!q.empty())
{
x=q.front(),q.pop();vis[x]=0;
for(int i=last[x];i;i=nxt[i])
if(dis[h[i]]>dis[x]+wis[i])
{
dis[h[i]]=dis[x]+wis[i];
if(!vis[h[i]])q.push(h[i]),vis[h[i]]=1;
}
}
cout<<dis[t];
return 0;
}
SIXTEENTH nim游戏
#include<iostream>
using namespace std;
int T,n,ans,x;
int main()
{
cin>>T;
while(T--)
{
cin>>n;
ans=0;
for(int i=1;i<=n;i++)cin>>x,ans^=x;
if(ans==0)cout<<"No\n";
else cout<<"Yes\n";
}
}