class PII implements Comparable<PII>{
int x;
int y;
public PII(int x,int y){
this.x=x;
this.y=y;
}
// 如果用到对象排序的话
public int compareTo(PII o){
return Integer.compare(x,o.x);//从小到大排序
// return Integer compare(o.x,x); 从大到小排序
}
}
public class Main{
static PII[] p=new PII[100010];
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(in.readLine());
for(int i=0;i<n;i++){
String[] strs=in.readLine().split(" ");
int x=Integer.parseInt(strs[0]);
int y=Integer.parseInt(strs[1]);
p[i]=new PII(x,y);
}
Arrays.sort(p);
}
}
void merge_sort(int q[],int l,int r){
if(l>=r)return;
int mid=l+r>>1;
merge_sort(q,l,mid);
merge_sort(q,mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid && j<=r)
if(q[i]<=q[j])tmp[k++]=q[i++]
else tmp[k++]=q[j++];
while(i<=mid) tmp[k++]=q[i++];
while(j<=r) tmp[k++]=q[j++];
for(i=l,j=0;i<=r;i++,j++)q[i]=tmp[j];
}
// 当j>i且q[i]>a[j]时
res+=mid-i+1;
bool check(int x){} //检查x是否满足某种性质
int bsearch_1(int l,int r){
while(l<r){
int mid=l+r>>1;
if(check(mid))r=mid;
else l=mid+1;
}
return l;
}
int bsearch_2(int l,int r){
while(l<r){
int mid=l+r+1>>1;
if(check(mid))l=mid;
else r=mid-1;
}
return l;
}
bool check(double x){} //检查x是否满足某种性质
double bsearch_3(double l,double r){
const double eps=1e-6;
while(r-l>eps){
double mid=(l+r)/2;
if(check(mid))r=mid;
else l=mid;
}
return l;
}
java版本高精度计算
import java.io.*;
import java.math.*;
public class Main{
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
String str=in.readLine();
BigInteger a=new BigInteger(str);
str=in.readLine();
BigInteger b=new BigInteger(str);
// 高精度加法
System.out.println(a.add(b));
// 高精度减法
System.out.println(a.subtract(b));
// 高精度乘法
System.out.println(a.multiply(b));
// 高精度除法
System.out.println(a.divide(b));
// 其他常用方法
// gcd最大公约数
// max,min,mod,pow,abs,sqrt
}
}
看题目要求随机应变
s[i]=s[i-1]+a[i]
s[r]-s[l-1]=a[l]+...+a[r]
B[l]+=c;B[r+1]-=c;
// 然后对B数组求和
s[i,j] = 第i行第j列格子左上部分所有元素的和
以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵的和为:
s[x2,y2] - s[x1-1,y2] - s[x2,y1-1] + s[x1-1,y1-1]
给以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵中的所有元素加上c:
s[x1,y1] += c, s[x2+1,y1] -= c,s[x1,y2+1] -= c, s[x2+1,y2+1] += c
然后对s数组求和就行
适用于在某个矩阵区间加上某个值后,求每个位置的值
求n的第K位数字: n>>k&1
返回n的最后一位1:lowbit(n) = n & -n
import java.io.*;
public class Main{
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(in.readLine());
System.out.println(lowbit(n));
}
static int lowbit(int x) {
return x & -x;
}
}
import java.io.*;
import java.util.*;
class PII implements Comparable<PII>{
int l;
int r;
public PII(int l,int r) {
this.l=l;
this.r=r;
}
public int compareTo(PII o) {
if(l>o.l)return 1;
else if(l==o.l&&r>o.r)return 1;
else return -1;
}
}
public class Main{
static int N=100010;
static PII[] p=new PII[N];
static int n;
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
n=Integer.parseInt(in.readLine());
String[] strs;
for(int i=0;i<n;i++) {
strs=in.readLine().split(" ");
int l=Integer.parseInt(strs[0]);
int r=Integer.parseInt(strs[1]);
p[i]=new PII(l,r);
}
merge();
}
static void merge() {
List<PII> res=new ArrayList<>();
Arrays.sort(p,1,n);
int st = (int)-2e9;
int ed = (int)-2e9;
for(int i=0;i<n;i++) {
if(ed<p[i].l) {
if(st!=-2e9)res.add(new PII(st,ed));
st=p[i].l;
ed=p[i].r;
}
else ed=Math.max(ed,p[i].r);
}
if(st!=-2e9)res.add(new PII(st,ed));
System.out.println(res.size());
}
}
// head存储链表头,e[]存储节点的值,ne[]存储节点的next指针,idx表示当前用到了哪个节点
int head,e[N],ne[N],idx;
//初始化
void init(){
head=-1;
idx=0;
}
//在链表头插入一个数a
void insert(){
e[idx]=a,ne[idx]=head,head=idx++;
}
//将头结点删除,需要保证头结点存在
void remove(){
head=ne[head];
}
// tt表示栈顶
int stk[N],tt=0;
//向栈顶插入一个数
stk[++tt]=x;
// 从栈顶弹出一个数
tt--;
//栈顶的值
stk[tt];
//判断栈是否为空,如果tt>0,则表示不为空
if(tt>0){
}
// hh表示对头,tt表示队尾
int q[N],hh=0,tt=-1;
//向队尾插入一个数
q[++tt]=x;
//从队头弹出一个数
hh++;
//判断队列是否为空,如果hh<=tt,则表示不为空
if(hh<=tt){
}
// 常见模型:找出每个数左边离它最近的比它大/小的数
int tt=0;
for(int i=1;i<=n;i++){
while(tt && check(stk[tt],i))tt--;
// while(tt && a[stk[tt]]>=a[i])tt--;
stk[++tt]=i;
}
// 常见模型:找出滑动窗口的最大值/最小值
int hh=0,tt=-1;
for(int i=0;i<n;i++){
while(hh<=tt&&check_out(q[hh]))hh++;// 判断队头是否滑出窗口
while(hh<=tt&&check(q[tt],i))tt--;
q[++tt]=i;
}
import java.io.*;
public class Main{
static int N=1000010;
static int[] a=new int[N];
static int[] q=new int[N];
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
String[] strs=in.readLine().split(" ");
int n=Integer.parseInt(strs[0]);
int k=Integer.parseInt(strs[1]);
strs=in.readLine().split(" ");
for(int i=0;i<n;i++){
a[i]=Integer.parseInt(strs[i]);
}
// 求滑动窗口最小值
int hh=0,tt=-1;
for(int i=0;i<n;i++){
while(hh<=tt&&q[hh]<i-k+1)hh++;
while(hh<=tt&&a[q[tt]]>=a[i])tt--;
q[++tt]=i;
if(i>=k-1)System.out.print(a[q[hh]]+" ");
}
System.out.println();
// 求滑动窗口最大值
hh=0;tt=-1;
for(int i=0;i<n;i++){
while(hh<=tt&&q[hh]<i-k+1)hh++;
while(hh<=tt&&a[q[tt]]<=a[i])tt--;
q[++tt]=i;
if(i>=k-1)System.out.print(a[q[hh]]+" ");
}
}
}
// s[]是长文本,p[]是模式串,n是s的长度,m是p的长度
// 求模式串的Next数组:
for(int i=2,j=0;i<=m;i++){
while(j && p[i]!=p[j+1]) j=ne[j];
if(p[i]==p[j+1])j++;
ne[i]=j;
}
// 匹配
for(int i=1,j=0;i<=n;i++){
while(j && s[i] != p[j+1]) j=ne[j];
if(s[i] == p[j+1])j++;
if(j==m)
{
j=ne[j];
}
}
// 插入一个字符串
import java.io.*;
public class Main{
static int N=100010;
static int[][] son=new int[N][26];
static int[] cnt=new int[N];
// 0号点既是根结点,又是空节点
// son[][]存储树中每个节点的子节点
// cnt[]存储以每个节点结尾的单词数量
static int idx;
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(in.readLine());
String[] strs;
for(int i=0;i<n;i++) {
strs=in.readLine().split(" ");
char op=strs[0].charAt(0);
String str=strs[1];
if(op=='I') {
insert(str);
}
else {
System.out.println(query(str));
}
}
}
// 插入一个字符串
static void insert(String str) {
int p=0;
for(int i=0;i<str.length();i++) {
int u=str.charAt(i)-'a';
if(son[p][u]==0)son[p][u]=++idx;
p=son[p][u];
}
cnt[p]++;
}
// 查询字符串出现的次数
static int query(String str) {
int p=0;
for(int i=0;i<str.length();i++) {
int u=str.charAt(i)-'a';
if(son[p][u]==0)return 0;
p=son[p][u];
}
return cnt[p];
}
}
(1)朴素并查集
int p[N]; // 存储每个点的祖宗节点
// 返回x的祖宗节点
int find(int x){
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
// 初始化,假定节点编号时1~n
for(int i=1;i<=n;i++) p[i]=i;
// 合并a和b所在的两个集合
p[find(a)]=find(b);
(2)维护size的并查集
int p[N],size[N];
// p[]存储每个点的祖宗节点,size[]只有祖宗节点的有意义,表示祖宗节点所在集合中的点的数量
// 返回x的祖宗节点
int find(int x){
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
// 初始化,假定节点编号是1~n
for(int i=1;i<=n;i++){
p[i]=i;
size[i]=1;
}
// 合并a和b所在的两个集合
size[find(b)] += size[find(a)];
p[find(a)] =find(b);
(3) 维护到祖宗节点距离的并查集
int p[N],d[N];
// p[]存储每个点的祖宗节点,d[x]存储x到p[x]的距离
// 返回x的祖宗节点
int find(int x){
if(p[x]!=x){
int u=find(p[x]);
d[x]+=d[p[x]];
p[x]=u;
}
return p[x];
}
// 初始化,假定节点编号是1~n
for(int i=1;i<=n;i++){
p[i]=i;
d[i]=0;
}
// 合并a和b所在的集合
p[find(a)]=find(b);
d[find(a)]=distance; //根据具体问题,初始化find(a)的偏移量
java用优先队列来模拟堆
import java.io.*;
import java.util.*;
public class Main{
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
Queue<Integer> q=new PriorityQueue<>();
}
}
java HashSet
import java.io.*;
import java.util.*;
class PII{
int x;
int y;
public PII(int x,int y) {
this.x=x;
this.y=y;
}
}
public class Main{
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
HashSet<PII> hs=new HashSet<PII>();
int n=Integer.parseInt(in.readLine());
String[] strs;
for(int i=0;i<n;i++) {
strs=in.readLine().split(" ");
int x=Integer.parseInt(strs[0]);
int y=Integer.parseInt(strs[1]);
hs.add(new PII(x,y));
}
for(PII p:hs) {
System.out.println(p.x+" "+p.y);
}
}
}
import java.io.*;
import java.util.*;
public class Main{
static int N=100010;
static int[] head=new int[N];
static int[] e=new int[N];
static int[] ne=new int[N];
static int[] w=new int[N];
static int idx;
static int m;
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
m=Integer.parseInt(in.readLine());
String[] strs;
Arrays.fill(head, -1);
for(int i=0;i<m;i++) {
strs=in.readLine().split(" ");
int a=Integer.parseInt(strs[0]);
int b=Integer.parseInt(strs[1]);
int c=Integer.parseInt(strs[2]);
add(a,b,c);
}
}
static void add(int a,int b,int c) {
e[idx]=b;w[idx]=c;ne[idx]=head[a];head[a]=idx++;
}
}
深度优先遍历
int dfs(int u){
st[u]=true;
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(!st[j])dfs(j);
}
}
宽度优先遍历
queue<int> q;
st[1]=true; //表示1号点已经被遍历过
q.push(1);
while(q.size()){
int t=q.front();
q.pop();
for(int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
if(!st[j]){
st[j]=true; //表示点j已经被遍历过
q.push(j);
}
}
}
bool topsort(){
int hh=0,tt=-1;
//d[i]存储点i的入度
for(int i=1;i<=n;i++){
if(d[i]==0){
q[++tt]=i;
}
}
while(hh<=tt){
int t=q[hh++];
for(int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
if(--d[j]==0)
q[++tt]=j;
}
}
return tt==n-1;
}
int g[N][N]; //存储每条边
int dist[N]; //存储1号点到每个点的最短距离
bool st[N]; //存储每个点的最短路时候已经确定
// 求1号点到n号点的最短路,如果不存在就返回-1
int dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[1]=0;
for(int i=0;i<n-1;i++){
int t=-1; // 在还未确认最短路的点中,寻找距离最小的点
for(int j=1;j<=n;j++){
if(!st[j]&&(t==-1||dist[t]>dist[j])
t=j;
}
// 用t更新其他点的距离
for(int j=1;j<=n;j++){
dist[j]=min(dist[j],dist[t]+g[t][j]);
}
st[t]=true;
}
if(dist[n]==0x3f3f3f3f) return -1;
return dist[n];
}
typedef pair<int,int> PII;
int n; // 点的数量
int h[N],w[N],e[N],ne[N],idx; // 邻接表存储所有边
int dist[N]; // 存储所有点到1号点的距离
bool st[N]; // 存储每个点的最短距离是否已确定
// 求1号点到n号点的最短距离,如果不存在,则返回-1
int dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[1]=0;
priority_queue<PII,vector<PII>,greater<PII>> heap;
heap.push({0,1}) //first存储距离,second存储节点编号
while(heap.size()){
auto t=heap.top();
heap.pop();
int ver = t.second,distance=t.first;
if(st[ver]) continue;
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>distance+w[i]){
dist[j]=distance+w[i];
heap.push({dist[j],j});
}
}
}
if(dist[n]==0x3f3f3f3f) return -1;
return dist[n];
}
int n; // 总点数
int h[N],w[N],e[N],ne[N],idx; // 邻接表存储所有边
int dist[N],cnt[N]; // 存储每个点到1号点的最短距离
bool st[N]; //存储每个点是否在队列中
// 求1号点到n号点的最短路距离,如果从1号点无法走到n号点则返回-1
int spfa(){
memset(dist,0x3f,sizeof dist);
dist[1]=0;
queue<int> q;
q.push(1);
st[1]=true;
while(q.size()){
auto t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>dist[t]+w[i]){
dist[j]=dist[t]+w[i];
if(!st[j]){ // 如果队列中已存在j,则不需要将j重复插入
q.push(j);
st[j]=true;
}
}
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int n; // 总点数
int h[N],w[N],e[N],ne[N],idx; // 邻接表存储所有边
int dist[N],cnt[N]; // dist[x]存储1号点到x的最短距离,cnt[x]存储1到x的最短路中经过的点数
bool st[N]; // 存储每个点是否在队列中
// 如果存在负环,则返回true,否则返回false;
bool spfa(){
// 不需要初始化dist数组
// 原理:如果某条最短路径上有n个点(除了自己),那么加上自己之后一共有n+1个点,由抽屉原理一定有两个点相同,所以存在环。
queue<int> q;
for(int i=1;i<=n;i++){
q.push(i);
st[i]=true;
}
while(q.size()){
auto t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>dist[t]+w[i]){
dist[j]=dist[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n) return ture; // 如果从1号点到x的最短路中包含至少n个点(不包括自己),则说明存在环
if(!st[j]){
q.push(j);
st[j]=true;
}
}
}
}
return false;
}
多源最短路
初始化:
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) d[i][j]=0;
else d[i][j]=INF;
}
}
// 算法结束后,d[a][b]表示a到b的最短距离
void floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
}
适用于点数较小的求生成树
int n; // n表示点数
int g[N][N]; // 邻接矩阵,存储所有边
int dist[N]; //存储其他点到当前最小生成树的距离
bool st[N]; //存储每个点是否已经在生成树中
//如果图不连通,则返回INF(值是0x3f3f3f3f),否则返回最小生成树的树边权重之和
int prim(){
memset(dist,0x3f,sizeof dist);
int res=0;
for(int i=0;i<n;i++){
int t=-1;
for(int j=1;j<=n;j++){
if(!st[j]&&(t==-1 || dist[t]>dist[j])
t=j;
}
if(i && dist[t] == INF) return INF;
if(i) res += dist[t];
st[t] = true;
for(int j=1;j<=n;j++)dist[j]=min(dist[j],g[t][j]);
}
}
适用于点数较大的求最小生成树
int n,m; // n是点数,m是边数
int p[N]; // 并查集的父节点数组
class Edge Comparable<Edge>{ // 存储边
int a;
int b;
int w;
public Edge(int a,int b,int w){
this.a=a;
this.b=b;
this.w=w;
}
public int compareTo(Edge o){
return Integer.compare(w,o.w);
}
}
Edge[] edges=new Edge[M];
int find(int x) //并查集核心操作
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int kruskal(){
Arrays.sort(edges,edges+m);
for(int i=1;i<=n;i++) p[i]=i; //初始化并查集
int res=0,cnt=0;
for(int i=0;i<m;i++){
int a=edgs[i].a,b=edges[i].b,w=edges[i].w;
a=find(a);b=find(b);
if(a!=b){
p[a]=b;
res+w;
cnt++;
}
}
if(cnt<n-1)return INF;
return res;
}
int n; // n表示点数
int h[N],e[M],ne[M],idx; // 邻接表存储图
int color[N]; //表示每个点的颜色,-1表示未染色,0表示白色,1表示黑色
// 参数: u表示当前节点,c表示当前点的颜色
bool dfs(int u,int c){
color[u]=c;
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(color[j] == -1){
if(!dfs(j,!c)) return false;
}
else if(color[j] == c) return false;
}
return true;
}
bool check(){
memset(color,-1,sizeof color);
bool flag=true;
for(int i=1;i<=n;i++){
if(color[i]==-1){
if(!dfs(i,0)){
flag=false;
break;
}
}
}
return flag;
}
int n1,n2; // n1表示第一个集合中的点数,n2表示第二个集合中的点数
int h[N],e[M],ne[M],idx; // 邻接表存储所有边,匈牙利算法中只会用到从第一个集合指向第二个集合的边,所以这里只用存一个方向的边
int match[N]; // 存储第二个集合中的每个点当前匹配的第一个集合中的点是哪个
bool st[N]; // 表示第二个集合中的每个点是否已经被遍历过
bool find(int x){
for(int i=h[x];i!=-1;i=ne[i]){
int j=e[i];
if(!st[j]){
st[j]=true;
if(match[j]==0 || find(match[j])){
match[j]=x;
return true;
}
}
}
return false;
}
// 求最大匹配数,依次枚举第一个集合中的每个点能否匹配第二个集合中的点
int res=0;
for(int i=1;i<=n1;i++){
memset(st,false,sizeof st);
if(find(i))res++;
}
bool is_prime(int x){
if(x<2)return false;
for(int i=2;i<=x/i;i++){
if(x%i==0)
return false;
}
return true;
}
void divide(int x){
for(int i=2;i<=x/i;i++){
if(x%i==0){
int s=0;
while(x%i==0) x/=i,s++;
System.out.println(i+" "+s);
}
}
if(x>1)System.out.println(x+" "+1);
}
int primes[N],cnt; // primes[]存储所有素数
bool st[N]; // st[x]存储x是否被筛掉
void get_primes(int n){
for(int i=2;i<=n;i++){
if(st[i])continue;
primes[cnt++]=i;
for(int j=i+i;j<=n;j+=i){
st[j]=true;
}
}
}
int primes[N],cnt; // primes[]存储所有素数
bool st[N]; // st[x]存储x是否被筛掉
void get_primes(int n){
for(int i=2;i<=n;i++){
if(!st[i])primes[cnt++]=i;
for(int j=0;primes[j]<=n/i;j++){
st[primes[j]*i]=true;
if(i%primes[j]==0)break;
}
}
}
vector<int> get_divisors(int x){
vector<int> res;
for(int i=1;i<=x/i;i++){
if(x%i==0){
res.push_back(i);
if(i!=x/i)res.push_back(x/i);
}
}
sort(res.begin(),res.end());
return res;
}
如 果 N = p 1 c 1 ∗ p 2 c 2 ∗ . . . ∗ p k c k 约 数 个 数 : ( c 1 + 1 ) ∗ ( c 2 + 1 ) ∗ . . . ∗ ( c k + 1 ) 约 数 之 和 : ( p 1 0 + p 1 1 + . . . + p 1 c 1 ) ∗ . . . ∗ ( p k 0 + p k 1 + . . . + p k c k ) 如果N=p_1^{c_1}*p_2^{c_2}*...*p_k^{c_k} \\ 约数个数:(c_1+1)*(c_2+1)*...*(c_k+1) \\ 约数之和:(p_1^0+p_1^1+...+p_1^{c_1})*...*(p_k^0+p_k^1+...+p_k^{c_k}) 如果N=p1c1∗p2c2∗...∗pkck约数个数:(c1+1)∗(c2+1)∗...∗(ck+1)约数之和:(p10+p11+...+p1c1)∗...∗(pk0+pk1+...+pkck)
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
求某个数的欧拉函数
如 果 N = p 1 a 1 p 2 a 2 . . . p m a m ϕ ( N ) = N × p 1 − 1 p 1 × p 2 − 1 p 2 × . . . × p m − 1 p m 如果N=p_1^{a_1}p_2^{a_2}...p_m^{a_m} \\ \phi(N)=N \times \frac{p_1-1}{p_1} \times \frac{p_2-1}{p_2} \times ... \times \frac{p_m-1}{p_m} 如果N=p1a1p2a2...pmamϕ(N)=N×p1p1−1×p2p2−1×...×pmpm−1
int phi(int x){
int res=x;
for(int i=2;i<=x/i;i++){
if(x%i==0){
res=res/i*(i-1);
while(x%i==0)x/=i;
}
}
if(x>1)res=res/x*(x-1);
return res;
}
求1-n的每个数的欧拉函数
int primes[N],cnt; // primes[]存储所有素数
int euler[N]; // 存储每个数的欧拉函数
bool st[N]; // st[x]存储x是否被筛掉
void get_eulers(int n){
euler[1]=1;
for(int i=2;i<=n;i++){
if(!st[i]){
primes[cnt++]=i;
euler[i]=i-1;
}
for(int j=0;primes[j]<=n/i;j++){
int t=primes[j]*i;
st[t]=true;
if(i%primes[j]==0){
euler[t]=euler[i] * primes[j];
break;
}
euler[t]=euler[i]*(primes[j]-1);
}
}
}
求 m k m o d p m^kmodp mkmodp,时间复杂度为O(logk)
int qmi(int m,int k,int p){
int res=1%p,t=m;
while(k){
if(k&1)res=res*t%p;
t=t*t%p;
k>>=1;
}
return res;
}
// 求x,y,使得ax+by=gcd(a,b)
int exgcd(int a,int b,int &x,int &y){
if(!b){
x=1;y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return d;
}
// a[N][N]是增广矩阵
int gauss(){
int c,r;
for(c=0,r=0;c<n;c++){
int t=r;
for(int i=r;i<n;i++) // 找到绝对值最大的行
if(fabs(a[i][c])>fabs(a[t][c])){
t=i;
}
if(fabs(a[t][c])<eps)continue;
for(int i=c;i<=n;i++) swap(a[t][i],a[r][i]); //将绝对值最大的行换到最顶端
for(int i=n;i>=c;i--) a[r][i]/=a[r][c]; // 将当前行的首位变成1
for(int i=r+1;i<n;i++){ // 用当前行将下面所有的列消成0
if(fabs(a[i][c])>eps){
for(int j=n;j>=c;j--){
a[i][j]-=a[r][j]*a[i][c];
}
}
}
r++;
}
if(r<n){
for(int i=r;i<n;i++){
if(fabs(a[i][n]>eps)
return 2; // 无解
}
return 1; //有无穷组解
}
for(int i=n-1;i>=0;i--){
for(int j=i+1;j<n;j++){
a[i][n]-=a[i][j]*a[j][n];
}
}
return 0;// 有唯一解
}
// c[a][b]表示从a个苹果中选b个的方案数
for(int i=0;i<N;i++){
for(int j=0;j<=i;j++){
if(!j)c[i][j]=1;
else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
来源:https://www.acwing.com/