头文件
#include <iostream> <fstream> <sstream> <cstdlib> <cstdio> <cmath> <string>
#include <cstring> <algorithm> <queue> <stack> <vector> <set> <map> <list>
#include <iomanip> <cctype> <cassert> <bitset> <ctime> <climits> <complex>
//#include <chrono> <random> <unordered_set> <unordered_map>
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization("unroll-loops")
简易版
const int MAXSIZE=100000;
char buf[MAXSIZE],*p1=buf,*p2=buf;
char obuf[1<<23],*O=obuf;
#define nc p1==p2&&(p2=(p1=buf)+fread\
(buf,1,MAXSIZE,stdin),p1==p2)?EOF:*p1++
inline void read(int &x) {
bool f=0; char ch=nc; x=0;
while(!isdigit(ch)) {if(ch=='-')f=1;ch=nc;}
while(isdigit(ch)) x=x*10+ch-'0',ch=nc;
if(f) x=-x;
}
inline void print(int x) {
if(x<0) *O++='-', x=-x;
if(x>9) print(x/10);
*O++=x%10+'0';
}
fwrite(obuf,O-obuf,1,stdout); // 末尾
爆炸版
namespace IO{
#define BUF_SIZE 100000
#define OUT_SIZE 100000
#define ll long long
bool IOerror=0;
inline char nc(){
static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
if (p1==pend){
p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin);
if (pend==p1){IOerror=1;return -1;}
}
return *p1++;
}
inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
inline void read(int &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
inline void read(ll &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
inline void read(double &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (ch=='.'){
double tmp=1; ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0');
}
if (sign)x=-x;
}
inline void read(char *s){
char ch=nc();
for (;blank(ch);ch=nc());
if (IOerror)return;
for (;!blank(ch)&&!IOerror;ch=nc())*s++=ch;
*s=0;
}
inline void read(char &c){
for (c=nc();blank(c);c=nc());
if (IOerror){c=-1;return;}
}
//fwrite->write
struct Ostream_fwrite{
char *buf,*p1,*pend;
Ostream_fwrite(){buf=new char[BUF_SIZE];p1=buf;pend=buf+BUF_SIZE;}
void out(char ch){
if (p1==pend){
fwrite(buf,1,BUF_SIZE,stdout);p1=buf;
}
*p1++=ch;
}
void print(int x){
static char s[15],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1);
}
void println(int x){
static char s[15],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1); out('\n');
}
void print(ll x){
static char s[25],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1);
}
void println(ll x){
static char s[25],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1); out('\n');
}
void print(double x,int y){
static ll mul[]={1,10,100,1000,10000,100000,1000000,10000000,100000000,
1000000000,10000000000LL,100000000000LL,1000000000000LL,
10000000000000LL,100000000000000LL,1000000000000000LL,
10000000000000000LL,100000000000000000LL};
if (x<-1e-12)out('-'),x=-x;x*=mul[y];
ll x1=(ll)floor(x); if (x-floor(x)>=0.5)++x1;
ll x2=x1/mul[y],x3=x1-x2*mul[y]; print(x2);
if (y>0){out('.'); for (size_t i=1;i<y&&x3*mul[i]<mul[y];out('0'),++i); print(x3);}
}
void println(double x,int y){print(x,y);out('\n');}
void print(char *s){while (*s)out(*s++);}
void println(char *s){while (*s)out(*s++);out('\n');}
void flush(){if (p1!=buf){fwrite(buf,1,p1-buf,stdout);p1=buf;}}
~Ostream_fwrite(){flush();}
}Ostream;
inline void print(int x){Ostream.print(x);}
inline void println(int x){Ostream.println(x);}
inline void print(char x){Ostream.out(x);}
inline void println(char x){Ostream.out(x);Ostream.out('\n');}
inline void print(ll x){Ostream.print(x);}
inline void println(ll x){Ostream.println(x);}
inline void print(double x,int y){Ostream.print(x,y);}
inline void println(double x,int y){Ostream.println(x,y);}
inline void print(char *s){Ostream.print(s);}
inline void println(char *s){Ostream.println(s);}
inline void println(){Ostream.out('\n');}
inline void flush(){Ostream.flush();}
#undef ll
#undef OUT_SIZE
#undef BUF_SIZE
};
using namespace IO;
注意结果保存在 aaa 数组里,用 a[0]a[0]a[0] 进行加减,局限于先加减后除
void div(int x){
ll tmp = 0;
for(int i=0; i<=p; i++){
tmp = tmp * 1000000000 + a[i];
a[i] = tmp / x; tmp %= x;
}
}
printf("%d.", a[0]);
for(int i=1; i<=p; i++) printf("%09d", a[i]);
1. __builtin_popcount(unsigned int n)
判断 nnn 的二进制中有多少个 111
int n = 15; //二进制为1111
cout<< __builtin_popcount(n) <<endl; //输出4
2. __builtin_ffs(unsigned int n)
判断 nnn 的二进制末尾最后一个 111 的位置
int n = 1; //1
int m = 8; //1000
cout<< __builtin_ffs(n) <<endl; //输出1
cout<< __builtin_ffs(m) <<endl; //输出4
3. __builtin_ctz(unsigned int n)
判断 nnn 的二进制末尾后面 000 的个数
int n = 1; //1
int m = 8; //1000
cout<< __builtin_ctzll(n) <<endl; //输出0
cout<< __builtin_ctz(m) <<endl; //输出3
4. __builtin_clz(unsigned int n)
返回前导的 000 的个数
PS:那么用此方法可以计算出第一个1的位置
int n = 1; //1
int m = 8; //1000
cout<< 32 - __builtin_clz(n) <<endl; //输出1
cout<< 64 - __builtin_clzll(m) <<endl; //输出4
5. __builtin_parity(unsigned int n)
判断 nnn 的二进制中 111 的个数的奇偶性
int n = 15; //二进制为1111
int m = 7; //111
cout<< __builtin_parity(n) <<endl; //偶数个,输出0
cout<< __builtin_parity(m) <<endl; //奇数个,输出1
方法一:scanf()
读入 char[]
使用方法:
char str[1024];
scanf("%[^\n]", &str);
getchar();
说明:在scanf
函数中,可以使用%c
来读取一个字符,使用%s
读取一个字符串, 但是读取字符串时不忽略空格,读字符串时忽略开始的空格,并且读到空格为止,因此只能读取一个单词,而不是整行字符串。
其实scanf
函数也可完成这样的功能,而且还更强大。这里主要介绍一个参数,%[ ]
,这个参数的意义是读入一个字符集合。[ ]
是个集合的标志,因此%[ ]
特指读入此集合所限定的那些字符,比如%[A-Z]
是输入大写字母,一旦遇到不在此集合的字符便停止。如果集合的第一个字符是"^"
,这说明读取不在"^"
后面集合的字符,既遇到"^"
后面集合的字符便停止。注意此时读入的字符串是可以含有空格的,而且会把开头的空格也读进来。
注意:如果要循环的多次从屏幕上读取一行的话,就要在读取一行后,在用%c
读取一个字符,将输入缓冲区中的换行符给读出来。否则的话,在下一次读取一行的时候,第一个就遇到'\n'
,匹配不成功就直接返回了。这里可以用scanf()
或者getchar()
函数读取换行符。
方法二:getchar()读入char[]
使用方法:
char str[1024];
int i = 0;
while((str[i]=getchar())!='\n') i++;
getchar();
说明:这样一个一个读也可以,也会把开头的空格读进来。最后也需要考虑换行符,使用getchar()
读出来。
方法三:gets()读入char[]
使用方法:
char str[1024];
gets(str);
说明:感觉这个就是多个getchar
的集合函数,很好用。功能是从标准输入键盘上读入一个完整的行(从标准输入读,一直读到遇到换行符),把读到的内容存入括号中指定的字符数组里,并用空字符'\0'
取代行尾的换行符'\n'
。读入时不需要考虑换行符。
方法四:getline()读入string或char[]
使用方法:
string str;
getline(cin, str); //读入string
char str2[1024];
cin.getline(str2, 1024); //读入char数组
说明:这是比较常用的方法,cin.getline
第三个参数表示间隔符,默认为换行符'\n'
。读入不需要考虑最后的换行符。
方法五:get()读入char[]
使用方法:
char str3[1024];
cin.get(str3,1024);//读入char数组
说明:get
函数读入时需要考虑最后的换行符,也就是说,如果用get
读入多行数据,要把'\n'
另外读出来,一般使用cin.get(str,1024).get();
来读入多组数据。
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
用 rnd()rnd()rnd() 即可,括号内部是随机种子,也可以换成下面这个:
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
random_shuffle()
可以替换为:
shuffle(a+1, a+n+1, rnd);
atoi() 函数的原型为: int atoi(const char *str );
函数功能:把字符串转换成整型数
参数str:要进行转换的字符串
返回值:每个函数返回 int 值,此值由将输入字符作为数字解析而生成。 如果该输入无法转换为该类型的值,则atoi的返回值为 0
itoa() 函数的原型为: char *itoa( int value, char *string,int radix);
value:要转换的数据
string:目标字符串的地址
radix:转换后的进制数,可以是10进制、16进制等,范围必须在 2~36
下面是一个十进制转八进制的方法:
int main(){
int num = 10;
char str[100];
itoa(num, str, 8); //将整数10转换为八进制保存在str字符数组中
printf("%s\n", str);
system("pause");
return 0;
}
下面是一个十进制转二进制的方法:
int main(){
int num = 15;
char str[100];
int n = atoi(itoa(num, str, 2)); //先转换为二进制的字符串,再换为整数
printf("%d\n",n);
system("pause");
}
上一个排列即为prev_permutation(int *begin, int *end)
int main() {
char a[3]= {'a','b','c'};
for(int i=1; i<=6; i++) {
for(int j=0; j<3; j++) printf("%c ", a[j]);
printf("\n");
next_permutation(a, a+3);
}
}
模为质数
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod = 1e9 + 7; // 注意替换
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0);\
for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
namespace linear_seq{
const int N=10010;
ll res[N],base[N],_c[N],_md[N];
vector<ll> Md;
void mul(ll *a,ll *b,int k) {
rep(i,0,k+k) _c[i]=0;
rep(i,0,k) if (a[i]) rep(j,0,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
for (int i=k+k-1;i>=k;i--) if (_c[i])
rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
rep(i,0,k) a[i]=_c[i];
}
int solve(ll n,VI a,VI b) {// a 系数 b 初值 b[n+1]=a[0]*b[n]+...
ll ans=0,pnt=0;
int k=SZ(a);
assert(SZ(a)==SZ(b));
rep(i,0,k) _md[k-1-i]=-a[i];_md[k]=1;
Md.clear();
rep(i,0,k) if (_md[i]!=0) Md.push_back(i);
rep(i,0,k) res[i]=base[i]=0;
res[0]=1;
while ((1ll<<pnt)<=n) pnt++;
for (int p=pnt;p>=0;p--) {
mul(res,res,k);
if ((n>>p)&1) {
for (int i=k-1;i>=0;i--) res[i+1]=res[i];res[0]=0;
rep(j,0,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
}
}
rep(i,0,k) ans=(ans+res[i]*b[i])%mod;
if (ans<0) ans+=mod;
return ans;
}
VI BM(VI s) {
VI C(1,1),B(1,1);
int L=0,m=1,b=1;
rep(n,0,SZ(s)) {
ll d=0;
rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;
if (d==0) ++m;
else if (2*L<=n) {
VI T=C;
ll c=mod-d*powmod(b,mod-2)%mod;
while (SZ(C)<SZ(B)+m) C.pb(0);
rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
L=n+1-L; B=T; b=d; m=1;
} else {
ll c=mod-d*powmod(b,mod-2)%mod;
while (SZ(C)<SZ(B)+m) C.pb(0);
rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
++m;
}
}
return C;
}
int gao(VI a,ll n){
VI c=BM(a);
c.erase(c.begin());
rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;
return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
}
};
int main() {
ll n; vector <int> v;
v.push_back(0); v.push_back(0);
v.push_back(3); v.push_back(30);
v.push_back(195); v.push_back(1050);
v.push_back(5103);
while(~scanf("%lld", &n)) {
printf("%lld\n",linear_seq::gao(v,n-1)%mod);
}
}
O(logn):O(logn):O(logn):
ll mult(ll a, ll b, ll p) {
a %= p; b %= p;
ll ret = 0;
while(b) {
if(b & 1) ret = (ret + a) % p;
a = (a + a) % p;
b >>= 1;
}
return ret;
}
O(1):O(1):O(1):
ll qmul(ll a, ll b) {
return (a*b - (ll)((long double)a/mod*b)*mod+mod)%mod;
}
Montgomery modular multiplication:
const int mod = 1e9 + 7;
typedef unsigned long long ull;
typedef __uint128_t L;
struct FastMod {
ull b, m;
FastMod(ull b) : b(b), m(ull((L(1) << 64) / b)) {}
inline ull reduce(ull a) {
return a - (ull)((L(m) * a) >> 64) * b;
}
} F(mod);
简介
检测一个链表是否有环(循环节),如果有,确定环的起点以及环的长度
复杂度
时间复杂度:O(n+m)O(n+m)O(n+m)
空间复杂度:O(1)O(1)O(1)
nnn 为起点 SSS 到环入口 PPP 的距离,mmm 为环的长度
结论
①①①:环检测
两个指针 ttt 和 hhh,ttt 移动速度为 111,hhh 移动速度为 222,判断是否相遇
②②②:找出环的入口节点
两个指针相遇后,将 ttt 重新放到链表头,然后两个指针速度都为 111,再次相遇后,所在位置即为入口节点
③③③:计算环长度
两个指针都放在入口节点后,ttt 移动速度为 111,hhh 移动速度为 000,再次相遇,即可计算出环长度
计算入口节点及环长度:
const ll mod = (1ll << 40);
inline ll nxt(ll x){
return (x + (x >> 20) + 12345ll) % mod;
}
signed main() {
ll s0 = 0x600DCAFE, cnt = 0, num = 0;
ll t = s0, h = s0;
while(true){
t = nxt(t), h = nxt(nxt(h));
++cnt;
if(!(t & 1)) ++num;
if(t == h) break;
}
t = s0, cnt = num = 0;
while(true){
t = nxt(t), h = nxt(h);
++cnt;
if(!(t & 1)) ++num;
if(t == h) break;
}
ll st_cyc = cnt, st_num = num;
cnt = num = 0;
while(true){
t = nxt(t);
// h = nxt(h);
++cnt;
if(!(t & 1)) ++num;
if(t == h) break;
}
ll len_cyc = cnt, ans_cyc = num;
deb(st_cyc); deb(st_num);
puts("-----------");
deb(len_cyc); deb(ans_cyc);
}
insert / clear 性能优化
当插入元素过多时,发生了哈希碰撞,碰撞开链到一定的阈值,触发了增加 bucketbucketbucket,进而触发了 rehashrehashrehash
因此,reservereservereserve 可以用来预留元素个数,rehashrehashrehash 根据提供的元素个数预留足够的bucket数目
unordered_map <int, int> mp;
mp.reserve(2e7);
mp.rehash(2e7);
同时,unordered_mapunordered\_mapunordered_map 每清空一次会遍历删除所有内容,可以替换为 swapswapswap
unordered_map <int, int> mp1;
mp.swap(mp1);
时间复杂度即可降为 O(1)O(1)O(1)
重载
unordered_mapunordered\_mapunordered_map 是哈希表的机制,也就是每个 keykeykey 会生成一个哈希码,根据哈希码来判断元素是否相同,故必须提供产生哈希码的函数,但是哈希码相同并不一定代表两个元素相同,所以还要实现 ====== 操作符。
以下用三种方式重写哈希:
①:手动重写
②:调用 boostboostboost 库函数(要手动下载 boostboostboost 库)
③:简单哈希
template <typename T>
inline void hash_combine(std::size_t &seed, const T &val) {
seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
// auxiliary generic functions to create a hash value using a seed
template <typename T> inline void hash_val(std::size_t &seed, const T &val) {
hash_combine(seed, val);
}
template <typename T, typename... Types>
inline void hash_val(std::size_t &seed, const T &val, const Types &... args) {
hash_combine(seed, val);
hash_val(seed, args...);
}
template <typename... Types>
inline std::size_t hash_val(const Types &... args) {
std::size_t seed = 0;
hash_val(seed, args...);
return seed;
}
struct node {
string str;
int num;
node(string _str, int _num):str(_str), num(_num) {}
bool operator == (const node &A) const {
return (str==A.str && num==A.num);
}
};
struct node_hash {
size_t operator() (const node &A) const {
return hash_val(A.str, A.num); // 重写
// return hash<string>()(A.str) ^ hash<int>()(A.num); // 简单
}
};
unordered_map <node, int, node_hash> mp;
signed main() {
mp[node("wpf", 666)] = 11;
mp[node("zzz", 123)] = 22;
printf("%d\n", (*mp.begin()).first.num);
printf("%d\n", (*mp.begin()).second);
deb(mp[node("zzz", 123)]);
}
常用函数
bit.size() 返回大小(位数)
bit.count() 返回1的个数
bit.any() 返回是否有1
bit.none() 返回是否没有1
bit.set() 全都变成1
bit.set(p) 将第p + 1位变成1(bitset是从第0位开始的!)
bit.set(p, x) 将第p + 1位变成x
bit.reset() 全都变成0
bit.reset(p) 将第p + 1位变成0
bit.flip() 全都取反
bit.flip(p) 将第p + 1位取反
bit.to_ulong() 返回它转换为unsigned long的结果,如果超出范围则报错
bit.to_ullong() 返回它转换为unsigned long long的结果,如果超出范围则报错
bit.to_string() 返回它转换为string的结果
构造函数
bitset<4> bitset1; //无参构造,长度为4,默认每一位为0
bitset<8> bitset2(12); //长度为8,二进制保存,前面用0补充
string s = "100101";
bitset<10> bitset3(s); //长度为10,前面用0补充
char s2[] = "10101";
bitset<13> bitset4(s2); //长度为13,前面用0补充
注意:
用字符串构造时,字符串只能包含 ‘0’ 或 ‘1’ ,否则会抛出异常。
构造时,需在<>中表明bitset 的大小(即size)。
在进行有参构造时,若参数的二进制表示比bitset的size小,则在前面用0补充(如上面的栗子);若比bitsize大,参数为整数时取后面部分,参数为字符串时取前面部分(如下面栗子):
bitset<2> bitset1(12);
string s = "100101";
bitset<4> bitset2(s); //s的size=6,而bitset的size=4,只取前面部分,即1001
char s2[] = "11101";
bitset<4> bitset3(s2); //与bitset2同理,只取前面部分,即1110
cout << bitset1 << endl; //00
cout << bitset2 << endl; //1001
cout << bitset3 << endl; //1110
可用函数
bitset<8> foo ("10011011");
cout << foo.count() << endl; //5 (count函数用来求bitset中1的位数,foo中共有5个1
cout << foo.size() << endl; //8 (size函数用来求bitset的大小,一共有8位
cout << foo.test(0) << endl; //true (test函数用来查下标处的元素是0还是1
cout << foo.test(2) << endl; //false (同理,foo[2]为0,返回false
cout << foo.any() << endl; //true (any函数检查bitset中是否有1
cout << foo.none() << endl; //false (none函数检查bitset中是否没有1
cout << foo.all() << endl; //false (all函数检查bitset中是全部为1
补充说明一下:test函数会对下标越界作出检查,而通过 [ ] 访问元素却不会经过下标检查,所以,在两种方式通用的情况下,选择test函数更安全一些
另外,含有一些函数:
bitset<8> foo ("10011011");
cout << foo.flip(2) << endl; //10011111 (用于将参数位取反
cout << foo.flip() << endl; //01100000 (将bitset每一位全部取反
cout << foo.set() << endl; //11111111 (将bitset的每一位全部置为1
cout << foo.set(3,0) << endl; //11110111 (将第一参数位的元素置为第二参数的值
cout << foo.set(3) << endl; //11111111 (将参数下标处置为1
cout << foo.reset(4) << endl; //11101111 (将参数下标处置为0
cout << foo.reset() << endl; //00000000 (将bitset的每一位全部置为0
同样,它们也都会检查下标是否越界,如果越界就会抛出异常
1. substr()
对字符串进行截取
string s = "0123456789";
string sub1 = s.substr(5); // 从下标为5开始一直到结尾:sub1 = "56789"
string sub2 = s.substr(5, 3); // 从下标为5开始截取长度为3位:sub2 = "567"
2. c_str()
返回一个指向正规 CCC 字符串的指针, 内容与本 stringstringstring 串相同
注意这是一个临时指针
char str[20];
string s = "1234";
strcpy(str, s.c_str()); // 将 s拷贝到 str
printf("%s", s.c_str()); // 可以直接输出
3. replace()
用法一:
用 strstrstr 替换指定字符串从起始位置 pospospos 开始,长度为 lenlenlen 的字符
string& replace (size_t pos, size_t len, const string& str);
string s = "this@ is@ a test string!";
s = s.replace(s.find("@"), 1, ""); // 找到第一个@位置,替换长度为1的串为空
cout << s << endl; // "this is@ a test string!"
用法二:
用 strstrstr 替换 迭代器起始位置 到 结束位置 的字符
string& replace (const_iterator i1, const_iterator i2, const string& str);
string s = "this@ is@ a test string!";
s = s.replace(s.begin(), s.begin()+6, ""); // 用str替换从begin位置开始的6个字符
cout << s << endl; // "is@ a test string!"
用法三:
用 substrsubstrsubstr 的指定子串(给定起始位置和长度)替换从指定位置上的字符串
string& replace (size_t pos, size_t len, const string& str, size_t subpos, size_t sublen);
string s = "this@ is@ a test string!";
string substr = "12345";
// 用substr的指定子串(从1位置数共3个字符)替换从0到5位置上的 s
s = s.replace(0, 5, substr, substr.find("1"), 3);
cout << s << endl; // "123 is@ a test sting!"
4. replace_all()
replace_all()
: 进行字符串替换,并循环换到没有为止
replace_all_distinct
: 进行字符串替换,只换一次
string& replace_all(string& str, const string& old_value, const string& new_value) {
while(true) {
string::size_type pos(0);
if( (pos=str.find(old_value))!=string::npos )
str.replace(pos, old_value.length(), new_value);
else break;
}
return str;
}
string& replace_all_distinct(string& str, const string& old_value, string& new_value) {
for(string::size_type pos(0); pos!=string::npos; pos+=new_value.length()) {
if( (pos=str.find(old_value, pos))!=string::npos )
str.replace(pos, old_value.length(), new_value);
else break;
}
return str;
}
string str1 = "12212", str2 = "12212";
cout << replace_all(str1, "12", "21") << endl; // "22211"
cout << replace_all_distinct(str2, "12", "21") << endl; // "21221"
求: n! mod p\large n! \text{ mod } pn! mod p
时间复杂度:Θ(nlogn)\Theta(\sqrt n \log n)Θ(nlogn)
//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
struct Fast_fac {
static const int N=(1<<17)+5;int P;
inline int add(R int x,R int y){return 0ll+x+y>=P?0ll+x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
const double Pi=acos(-1.0);
struct cp{
double x,y;
inline cp(){}
inline cp(R double xx,R double yy):x(xx),y(yy){}
inline cp operator +(const cp &b)const{return cp(x+b.x,y+b.y);}
inline cp operator -(const cp &b)const{return cp(x-b.x,y-b.y);}
inline cp operator *(const cp &b)const{return cp(x*b.x-y*b.y,x*b.y+y*b.x);}
inline cp operator *(const double &b)const{return cp(x*b,y*b);}
inline cp operator ~()const{return cp(x,-y);}
}w[2][N];
int r[21][N],ifac[N],lg[N],inv[N];double iv[21];
void Pre(){
iv[0]=1;
fp(d,1,17){
fp(i,0,(1<<d)-1)r[d][i]=(r[d][i>>1]>>1)|((i&1)<<(d-1));
lg[1<<d]=d,iv[d]=iv[d-1]*0.5;
}
inv[0]=inv[1]=ifac[0]=ifac[1]=1;
fp(i,2,131072)inv[i]=mul(P-P/i,inv[P%i]),ifac[i]=mul(ifac[i-1],inv[i]);
for(R int i=1,d=0;i<131072;i<<=1,++d)fp(k,0,i-1)
w[1][i+k]=cp(cos(Pi*k*iv[d]),sin(Pi*k*iv[d])),
w[0][i+k]=cp(cos(Pi*k*iv[d]),-sin(Pi*k*iv[d]));
}
int lim,d;
void FFT(cp *A,int ty){
fp(i,0,lim-1)if(i<r[d][i])swap(A[i],A[r[d][i]]);
cp t;
for(R int mid=1;mid<lim;mid<<=1)
for(R int j=0;j<lim;j+=(mid<<1))
fp(k,0,mid-1)
A[j+k+mid]=A[j+k]-(t=w[ty][mid+k]*A[j+k+mid]),
A[j+k]=A[j+k]+t;
if(!ty)fp(i,0,lim-1)A[i]=A[i]*iv[d];
}
void MTT(int *a,int *b,int len,int *c){
static cp f[N],g[N],p[N],q[N];
lim=len,d=lg[lim];
fp(i,0,len-1)f[i]=cp(a[i]>>16,a[i]&65535),g[i]=cp(b[i]>>16,b[i]&65535);
fp(i,len,lim-1)f[i]=g[i]=cp(0,0);
FFT(f,1),FFT(g,1);
fp(i,0,lim-1){
cp t,f0,f1,g0,g1;
t=~f[i?lim-i:0],f0=(f[i]-t)*cp(0,-0.5),f1=(f[i]+t)*0.5;
t=~g[i?lim-i:0],g0=(g[i]-t)*cp(0,-0.5),g1=(g[i]+t)*0.5;
p[i]=f1*g1,q[i]=f1*g0+f0*g1+f0*g0*cp(0,1);
}
FFT(p,0),FFT(q,0);
fp(i,0,lim-1)c[i]=((((ll)(p[i].x+0.5)%P<<16)%P<<16)+\
((ll)(q[i].x+0.5)<<16)+((ll)(q[i].y+0.5)))%P;
}
void calc(int *a,int *b,int n,int k){
static int f[N],g[N],h[N],sum[N],isum[N];
int len=1;while(len<=n+n)len<<=1;
fp(i,0,n)f[i]=mul(a[i],mul(ifac[i],ifac[n-i]));
for(R int i=n-1;i>=0;i-=2)f[i]=P-f[i];
int t=dec(k,n);
fp(i,0,n+n)g[i]=add(i,t);
sum[0]=g[0];fp(i,1,n+n)sum[i]=mul(sum[i-1],g[i]);
isum[n+n]=ksm(sum[n+n],P-2);
fd(i,n+n,1)isum[i-1]=mul(isum[i],g[i]);
fp(i,1,n+n)g[i]=mul(isum[i],sum[i-1]);g[0]=isum[0];
fp(i,n+1,len-1)f[i]=0;fp(i,n+n+1,len-1)g[i]=0;
MTT(f,g,len,h);
int res=1,p1=k-n,p2=k;
fp(i,p1,p2)res=1ll*res*i%P;
res=dec(res,0);
fp(i,0,n)g[i]=(0ll+P+p1+i)%P;
sum[0]=g[0];fp(i,1,n)sum[i]=mul(sum[i-1],g[i]);
isum[n]=ksm(sum[n],P-2);
fd(i,n,1)isum[i-1]=mul(isum[i],g[i]);
fp(i,1,n)g[i]=mul(isum[i],sum[i-1]);g[0]=isum[0];
for(R int i=0;i<=n;p2=add(p2,1),++i)
b[i]=mul(h[i+n],res),res=mul(res,mul(g[i],p2+1));
}
int solve(int bl){
static int a[N],b[N],c[N];
int s=0;for(int p=bl;p;p>>=1)++s;a[0]=1,--s;
int qwq=ksm(bl,P-2);
for(int p=0;s>=0;--s){
if(p){
calc(a,b,p,p+1);
fp(i,0,p)a[p+i+1]=b[i];a[p<<1|1]=0;
calc(a,b,p<<1,mul(p,qwq));
p<<=1;fp(i,0,p)a[i]=mul(a[i],b[i]);
}
if(bl>>s&1){
fp(i,0,p)a[i]=mul(a[i],(1ll*bl*i+p+1)%P);
p|=1,a[p]=1;
fp(i,1,p)a[p]=mul(a[p],(1ll*bl*p+i)%P);
}
}
int res=1;
fp(i,0,bl-1)res=mul(res,a[i]);
return res;
}
int GetFac(int n){
int s=sqrt(n),res=solve(s);
fp(i,s*s+1,n)res=mul(res,i);
return res;
}
int Fac(int n){
if(n>P-1-n){
int res=ksm(GetFac(P-1-n),P-2);
return (P-1-n)&1?res:P-res;
}
return GetFac(n);
}
} sol;
int main(){
int n, P, T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &P);
sol.P = P, sol.Pre();
printf("%d\n", sol.Fac(n));
}
}