int run(int year) { if((year%4==0&&year%100!=0)||(year%400==0)) return 1; else return 0; }
**蓝桥杯函数:**
全排列函数:next_permutation(a.begin(), a.end())
stoi(s) 将字符串s转为数字
二分查找:binary_search(arr[],arr[]+size , indx)
__builtin_popcount(n) :n的⼆进制中1的个数
__builtin_ffs(n):返回最低的非 0 位的下标,下标从 1 还是计数,0未定义
__builtin_clz(n):返回从最高位开始连续的 0 的个数
__builtin_ctz(n):返回从最低位开始的连续的 0 的个数;如果传入 0 则行为未定义
1.判断一个数字x二进制下第i位是不是等于1。(最低第1位)
方法:if(((1<<(i−1))&x)>0) 将1左移i-1位,相当于制造了一个只有第i位 上是1,其他位上都是0的二进制数。然后与x做与运算,如果结果>0, 说明x第i位上是1,反之则是0。
2.将一个数字x二进制下第i位更改成1。
方法:x=x|(1<<(i−1)) 证明方法与1类似。
3.将一个数字x二进制下第i位更改成0。
方法:x=x&~(1<<(i−1))
4.把一个数字二进制下最靠右的第一个1去掉。
方法:x=x&(x−1)
按位或运算符(|)
运算规则:参加运算的两个数只要两个数中的一个为1,结果就为1。
即 0 | 0= 0 , 1 | 0= 1 , 0 | 1= 1 , 1 | 1= 1 。
异或运算符(^)
运算规则:参加运算的两个数,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。
即 0 ^ 0=0 , 0 ^ 1= 1 , 1 ^ 0= 1 , 1 ^ 1= 0 。
按位与运算符(&)
运算规则:只有两个数的二进制同时为1,结果才为1,否则为0。(负数按补码形式参加按位与运算)
即 0 & 0= 0 ,0 & 1= 0,1 & 0= 0, 1 & 1= 1。
fill()函数参数:fill(first,last,val); 、//可以相当于memset赋值 ,赋值随意。
ceil() 函数向上舍入为最接近的整数。
**提示**:如需向下舍入为最接近的整数,请查看 floor() 函数。
**提示**:如需对浮点数进行四舍五入,请查看 round() 函数。
#pragma GCC optimize(2)
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define CAS int cas;cin>>cas;while(cas--)
#define mem(a,b) memset(a,b,sizeof(a))
#define f(i,l,h) for(int i=l;i<=h;++i)
#define eps 1e-9
#define pi acos(-1.0)
#define pb push_back
#define se second
#define fi first
const int maxn=500005;
const int INF = 0x3f3f3f3f;
typedef pair pii;
typedef long long ll;
using namespace std;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(ll x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}
usin
inline int read(){//快读,可快了
int x=0,f=0;char ch=getchar();
while(!isdigit(ch))f|=ch=='-',ch=getchar();
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return f?-x:x;
}
ll quick(ll a,ll b,ll m) {
ll ans=1;
while(b) {
if(b&1)
ans=(a*ans)%m;
a=(a*a)%m;
b>>=1;
}
return ans;
}
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b) {
return a / gcd(a, b) * b;
}
#define mod 1000000007
ll fac[maxn],inv[maxn];
void init(){
fac[0] = inv[0] = 1;
fac[1] = inv[1] = 1;
for(int i = 2; i <= maxn - 9; ++i)// 一定要从2开始
fac[i] = fac[i-1] * i % mod,
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
for(int i = 1; i <= maxn - 9; ++i)
inv[i] = inv[i] * inv[i-1] % mod;
}
ll c(int n,int m){
if(m>n||m<0) return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
const int maxx = 1e6+10;
int prime[maxx+10];
bool vis[maxx+10];
int k=0;
void init(){
vis[0]=vis[1]=1;
for(int i=2;i<=maxx;i++){
if(vis[i]==0)prime[++k]=i,vis[i]=1;
for(int j=1;i*prime[j]<=maxx&&j<=k;j++){
vis[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
const int MAXN = 10000005 ;
#define int64_t long long
int64_t mulEx(int64_t a , int64_t b , int64_t Mod) {///logn快速乘
if(!a) return 0 ;
int64_t ans(0) ;
while(b)
{
if(b & 1) ans = (ans + a) % Mod;
a <<= 1 ;
a %= Mod ;
b >>= 1 ;
}
return ans ;
}
int64_t powEx(int64_t base , int64_t n , int64_t Mod)
{///快速幂
int64_t ans(1) ;
while(n)
{
if(n & 1) ans = mulEx(ans , base , Mod) ;
base = mulEx(base , base , Mod) ;
n >>= 1 ;
}
return ans ;
}
bool check(int64_t a , int64_t d , int64_t n)
{
if(n == a) return true ;
while(~d & 1) d >>= 1 ;
int64_t t = powEx(a , d , n) ;
while(d < n - 1 && t != 1 && t != n - 1)
{
t = mulEx(t , t , n) ;
d <<= 1 ;
}
return (d & 1) || t == n - 1 ;
}
bool isP(int64_t n)
{ ///判断大数是否是质数
if(n == 2) return true ;
if(n < 2 || 0 == (n & 1)) return false ;
static int p[5] = {2 , 3 , 7 , 61 , 24251} ;
for(int i = 0 ; i < 5 ; ++ i) if(!check(p[i] , n - 1 , n)) return false ;
return true ;
}
int64_t gcd(int64_t a , int64_t b)
{
if(a < 0) return gcd(-a , b) ;
return b ? gcd(b , a - b * (a / b)) : a ;
}
int64_t Pollard_rho(int64_t n , int64_t c)
{///大数分解质因数
int64_t i = 1 , k = 2 , x = rand() % n , y = x ;
while(true)
{
x = (mulEx(x , x , n) + c) % n ;
int64_t d = gcd(y - x , n) ;
if(d != 1 && d != n) return d ;
if(y == x) return n ;
if(++ i == k)
{
y = x ;
k <<= 1 ;
}
}
}
vectorFac, factCnt ;
///Fac存的是质因子,大小不一定按照顺序,有重复
void factorization(int64_t n)
{
if(n==1) return ;
if(isP(n))
{
Fac.push_back(n) ;
return ;
}
int64_t p(n) ;
while(p >= n) p = Pollard_rho(p , rand() % (n - 1) + 1) ;
factorization(p) ;
factorization(n / p) ;
}
map factMap ;
///遍历map的first表示因子,second表示次数
void getFactor(int64_t x)
{///不用判断是否是质数,但是比较费时间
/**因此最好先判断一下是否是质数**/
srand(time(0)) ;
//factCnt = 0 ;
factMap.clear() ;
factorization(x) ;
for(int i = 0; i < Fac.size(); ++i) ++ factMap[Fac[i]] ;
}
//求每个数最小质因子
int cnt=0,lim=1e6+5;
void getprime(){
int cnt=0;
isprime[1]=1;
for(int i=2;i<=lim;i++){
if(isprime[i]==0){
prime[++cnt]=i,isprime[i]=i;
}
for(int j=1;j<=cnt&&i*prime[j]<=lim;j++){
isprime[i*prime[j]]=prime[j];
if(i%prime[j]==0){
break;
}
}
}
}
//分解质因数
while(x!=1) {
++pz[isprime[x]];
x/=isprime[x];
}
#include
using namespace std;
using ll = long long;
//通过知道前面的 n^1/3 的质数可以推断后面n^2/3的质数所以可以适当减小
const int N = 9e3;
const int M = 2; //为了减小内存可以不过是质数
const int PM = 2 * 3 * 5; //为了减小内存可以不过要按质数减小如去掉17
ll n;
bool np[N];
int prime[N], pi[N];
int phi[PM + 1][M + 1], sz[M + 1];
int getprime() {
int cnt = 0;
np[0] = np[1] = true;
pi[0] = pi[1] = 0;
for (int i = 2; i < N; ++i) {
if (!np[i]) prime[++cnt] = i;
pi[i] = cnt;
for (int j = 1; j <= cnt && i * prime[j] < N; ++j) {
np[i * prime[j]] = true;
if (i % prime[j] == 0) break;
}
}
return cnt;
}
void init() {
getprime();
sz[0] = 1;
for (int i = 0; i <= PM; ++i) phi[i][0] = i;
for (int i = 1; i <= M; ++i) {
sz[i] = prime[i] * sz[i - 1];
for (int j = 1; j <= PM; ++j) phi[j][i] = phi[j][i - 1] - phi[j / prime[i]][i - 1];
}
}
int sqrt2(ll x) {
ll r = (ll)sqrt(x - 0.1);
while (r * r <= x) ++r;
return int(r - 1);
}
int sqrt3(ll x) {
ll r = (ll)cbrt(x - 0.1);
while (r * r * r <= x) ++r;
return int(r - 1);
}
ll getphi(ll x, int s) {
if (s == 0) return x;
if (s <= M) return phi[x % sz[s]][s] + (x / sz[s]) * phi[sz[s]][s];
if (x <= prime[s] * prime[s]) return pi[x] - s + 1;
if (x <= prime[s] * prime[s] * prime[s] && x < N) {
int s2x = pi[sqrt2(x)];
ll ans = pi[x] - (s2x + s - 2) * (s2x - s + 1) / 2;
for (int i = s + 1; i <= s2x; ++i) ans += pi[x / prime[i]];
return ans;
}
return getphi(x, s - 1) - getphi(x / prime[s], s - 1);
}
ll getpi(ll x) {
if (x < N) return pi[x];
ll ans = getphi(x, pi[sqrt3(x)]) + pi[sqrt3(x)] - 1;
for (int i = pi[sqrt3(x)] + 1, ed = pi[sqrt2(x)]; i <= ed; ++i) ans -= getpi(x / prime[i]) - i + 1;
return ans;
}
ll lehmer_pi(ll x) { //小于等于n的素数有多少个
if (x < N) return pi[x];
int a = (int)lehmer_pi(sqrt2(sqrt2(x)));
int b = (int)lehmer_pi(sqrt2(x));
int c = (int)lehmer_pi(sqrt3(x));
ll sum = getphi(x, a) + (ll)(b + a - 2) * (b - a + 1) / 2;
for (int i = a + 1; i <= b; i++) {
ll w = x / prime[i];
sum -= lehmer_pi(w);
if (i > c) continue;
ll lim = lehmer_pi(sqrt2(w));
for (int j = i; j <= lim; j++) sum -= lehmer_pi(w / prime[j]) - (j - 1);
}
return sum;
}
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
init();
while (cin >> n && n) cout << lehmer_pi(n) << "\n";
return 0;
}
int nex[N];
void getnex(string s){
int k=-1;
int i=0;
nex[0]=-1;
int len=s.size();
while(i=lenp) return i-lenp;
else return -1;
}
#include
#include
#include
#define N 100010
using namespace std;
int n, m, ans = 0, cnt = 0;
int head[N], fa[N];
struct edge{
int u, v, w;
}e[N << 1];
inline int read(){
int s = 0;
char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s;
}
bool cmp(edge a, edge b){return a.w < b.w;}
int find(int x){ //!!!非常重要,并查集模板
if(x != fa[x]) fa[x] = find(fa[x]);
return fa[x];
}
void Kruskal(){ //Kruskal模板
sort(e + 1, e + m + 1, cmp);
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= m; i++){
int x = find(e[i].u), y = find(e[i].v);
if(x == y) continue; //如果两条边已经联通那么跳过
ans += e[i].w;
fa[x] = y; //将两个点合并
if(++cnt == n - 1) break; //当n - 1条边时结束
}
}
int main(){
n = read(); m = read();
for(int i = 1; i <= m; i++){
int x, y, z;
x = read(); y = read(); z = read();
e[i].u = x; e[i].v = y; e[i].w = z;
}
Kruskal();
printf("%d\n", ans);
return 0;
}
//Dijkstra算法
#define ll long long
const int N=200005;
const int inf=0x3f3f3f3f;
struct node{
int v;
int c;
bool operator <(const node &r)
const{
return c>r.c;
}
};
struct edge{
int v,val;
};
vector g[N];
int vis[N];
ll dis[N];
void dij(int n,int st){
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++) dis[i]=inf;
priority_queue q;
while(!q.empty())
q.pop();
dis[st]=0;
q.push({st,0});
node tmp;
while(!q.empty()){
tmp=q.top();
q.pop();
int u=tmp.v;
if(vis[u]) continue;
vis[u]=1;
for(int i=0;idis[u]+val){
dis[v]=dis[u]+val;
q.push({v,dis[v]});
}
}
}
}
//spfa算法
const int N=100005;
struct node{
int to,val;
}e;
vector g[N];
int vis[N],dis[N];
int n,m,st,ed;
queueq;
void spfa(int x){
for(int i=1;i<=n;i++) dis[i]=inf;
dis[x]=0;
q.push(x);
vis[x]=1;
cnt[st]=1;
while(!q.empty()){
int u=q.front();q.pop();vis[u]=0;
for(int i=0;idis[u]+w){
dis[v]=dis[u]+w;
if(!vis[v]){
vis[v]=1,q.push(v);
if(++cnt[v]>n)return false; //cnt[i] 为入队列次数,用来判定是否存在负环回路
}
}
}
}
}
//Tarjan算法
Tarjan(u,fa)//marge和find为并查集合并函数和查找函数
{
for each(u,v) //访问所有u子节点v
{
if(v==fa||vis[v]) continue;
Tarjan(v,u); //继续往下遍历
marge(u,v); //合并v到u上
标记v被访问过;
}
for each(u,e) //访问所有和u有询问关系的e
{
如果e被访问过;
u,e的最近公共祖先为find(e);
}
}
//倍增 ST
int d[N],p[N][22],w[N][22]; //w[i][j]: i为起点 到2^j内 单边最大权值
/*
void dfs(int u,int f){
for(int i=0;id[b]) swap(a,b);
for(int i=20;i>=0;i--){
if(d[a]<=d[b]-(1<=0;i--){
if(p[a][i]==p[b][i]) continue;
else{
a=p[a][i]; b=p[b][i];
}
}
return p[a][0];
}
#include
#include
#include
using namespace std;
const int N = 205;
vectorG[N];
int n,m;
int vis[N],pre[N]; //标记 存男朋友
int c[N]; //颜色
//用染色法判断这个图是否是二分图
bool Dfs(int u,int colour){
c[u] = colour;
for(int i = 0;i < G[u].size();i++){
int v = G[u][i];
if(c[v] == 0 && Dfs(v,3-colour)){
return true;
}else if(c[v] != 3-colour) {
printf("No\n");
return true;
}
}
return false;
}
//用匈牙利算法求出最大匹配数
bool dfs(int u){
for(int i = 0;i
void rmq_init(){
for(int i=1;i<=N;i++)
dp[i][0]=arr[i];//初始化
for(int j=1;(1<
const int MAXN = 5e5 + 5;
int nxt[MAXN*32][2], cnt;
int MAXBIT = 31,val[MAXN];
void init(){
nxt[0][0] = nxt[0][1] = 0;
cnt = 1;
}
void add(int n){
int cur = 0;
for (int i = MAXBIT; i >= 0; --i) {
int bit = (n >> i) & 1;
if (!nxt[cur][bit]) {
nxt[cnt][0] = nxt[cnt][1] = 0;
nxt[cur][bit] = cnt++;
}
cur = nxt[cur][bit];
}
val[cur] = n;
}
int que_mx(int x) {
int u = 0;
for (int i = MAXBIT; i >= 0; i--) {
int bit = ((x >> i) & 1);
if (nxt[u][bit ^ 1]) u = nxt[u][bit ^ 1];
else u = nxt[u][bit];
}
return val[u]^x;
}
int que_mi(int x) {
int u = 0;
for (int i = MAXBIT; i >= 0; i--) {
int bit = ((x >> i) & 1);
if (nxt[u][bit]) u = nxt[u][bit];
else u = nxt[u][bit ^ 1];
}
return val[u]^x;
}
int trie[N][26];
int cnt[N];
int id;
void insert(string s)
{
int p = 0;
for (int i = 0; i < s.size(); i++)
{
int x = s[i] - 'a';
if (trie[p][x] == 0) trie[p][x] = ++id;
p = trie[p][x];
}
cnt[p]++;
}
int find(string s)
{
int p = 0;
for (int i = 0; i < s.size(); i++)
{
int x = s[i] - 'a';
if (trie[p][x] == 0)return 0;
p = trie[p][x];
}
return cnt[p];
}
//定义
#define maxn 100007 //元素总个数
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
int Sum[maxn<<2],Add[maxn<<2];//Sum求和,Add为懒惰标记
int A[maxn],n;//存原数组数据下标[1,n]
/*建树*/
//PushUp函数更新节点信息 ,这里是求和
void PushUp(int rt){Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1];}
//Build函数建树
void Build(int l,int r,int rt){ //l,r表示当前节点区间,rt表示当前节点编号
if(l==r) {//若到达叶节点
Sum[rt]=A[l];//储存数组值
return;
}
int m=(l+r)>>1;
//左右递归
Build(l,m,rt<<1);
Build(m+1,r,rt<<1|1);
//更新信息
PushUp(rt);
}
/*点修改*/
void Update(int L,int C,int l,int r,int rt){//l,r表示当前节点区间,rt表示当前节点编号
if(l==r){//到叶节点,修改
Sum[rt]+=C;
return;
}
int m=(l+r)>>1;
//根据条件判断往左子树调用还是往右
if(L <= m) Update(L,C,l,m,rt<<1);
else Update(L,C,m+1,r,rt<<1|1);
PushUp(rt);//子节点更新了,所以本节点也需要更新信息
}
/*区间修改*/
void Update(int L,int R,int C,int l,int r,int rt){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
if(L <= l && r <= R){//如果本区间完全在操作区间[L,R]以内
Sum[rt]+=C*(r-l+1);//更新数字和,向上保持正确
Add[rt]+=C;//增加Add标记,表示本区间的Sum正确,子区间的Sum仍需要根据Add的值来调整
return ;
}
int m=(l+r)>>1;
PushDown(rt,m-l+1,r-m);//下推标记
//这里判断左右子树跟[L,R]有无交集,有交集才递归
if(L <= m) Update(L,R,C,l,m,rt<<1);
if(R > m) Update(L,R,C,m+1,r,rt<<1|1);
PushUp(rt);//更新本节点信息
}
/*区间查询*/
//下推标记
void PushDown(int rt,int ln,int rn){
//ln,rn为左子树,右子树的数字数量。
if(Add[rt]){
//下推标记
Add[rt<<1]+=Add[rt];
Add[rt<<1|1]+=Add[rt];
//修改子节点的Sum使之与对应的Add相对应
Sum[rt<<1]+=Add[rt]*ln;
Sum[rt<<1|1]+=Add[rt]*rn;
//清除本节点标记
Add[rt]=0;
}
}
int Query(int L,int R,int l,int r,int rt){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
if(L <= l && r <= R){
//在区间内,直接返回
return Sum[rt];
}
int m=(l+r)>>1;
//下推标记,否则Sum可能不正确
PushDown(rt,m-l+1,r-m);
//累计答案
int ANS=0;
if(L <= m) ANS+=Query(L,R,l,m,rt<<1);
if(R > m) ANS+=Query(L,R,m+1,r,rt<<1|1);
return ANS;
}
int a[MAXX],dp[MAXX]; // a数组为数据,dp[i]表示长度为i+1的LIS结尾元素的最小值
int main()
{
int n;
while(cin>>n)
{
for(int i=0; i>a[i];
dp[i]=INF; // 初始化为无限大
}
int pos=0; // 记录dp当前最后一位的下标
dp[0]=a[0]; // dp[0]值显然为a[0]
for(int i=1; idp[pos]) // 若a[i]大于dp数组最大值,则直接添加
dp[++pos] = a[i];
else // 否则找到dp中第一个大于等于a[i]的位置,用a[i]替换之。
dp[lower_bound(dp,dp+pos+1,a[i])-dp]=a[i]; // 二分查找
}
cout<
for(int i=1;i<=n;i++) cin>>a[i],mp[a[i]]=i;
for(int j=1;j<=n;j++) cin>>b[j];
int tot=0;dp[0]=mp[b[1]];
for(int i=2;i<=n;i++){
if(dp[tot]
for i=1..N
for j=V..v[i]//不用到0,因为若小于v[i],v[i]这个物品肯定·放不进去;肯定取上一个.
p[j]=MAX(p[j-volume[i]]+value[i],p[j]);
/*中国剩余定理模板*/
ll ai[maxn],bi[maxn];
//扩展欧几里得:一定存在整数 x, y 满足等式 a * x + b * y = gcd(a,b)
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0){ x=1, y=0; return a;}
ll gcd=exgcd(b,a%b,x,y);
ll tp=x;
x=y, y=tp-a/b*y;
return gcd;
}
ll mult(ll a,ll b,ll mod){
long long res=0;
while(b>0){
if(b&1) res=(res+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return res;
}
ll excrt(){
ll x,y;
ll ans=bi[1],M=ai[1];
for(int i=2;i<=n;++i){
ll a=M,b=ai[i],c=(bi[i]-ans%ai[i]+ai[i])%ai[i];
ll gcd=exgcd(a,b,x,y);
x=mult(x,c/gcd,b/gcd);
ans+=x*M;
M*=b/gcd;
ans=(ans%M+M)%M;
}
return (ans%M+M)%M;
}
int main(){
cin>>n;
for(int i=1;i<=n;++i)
cin>>ai[i]>>bi[i];
cout<
typedef long long ll;
//快速幂
ll quick_mod(ll a,ll b,ll m){
ll ans=1ll;
while(b){
if(b&1) ans=ans*a%m;
b>>=1;
a=a*a%m;
}
return ans;
}
//扩展欧几里得求逆元
ll exgcd(ll a,ll b,ll &x,ll &y){
if(a%b==0){
x=0ll;y=1ll;
return b;
}
ll v,tx,ty;
v=exgcd(b,a%b,tx,ty);
x=ty;
y=tx-a/b*ty;
return v;
}
//
ll inv(ll a,ll p){
if(!a) return 0ll;
ll x,y;
exgcd(a,p,x,y);
x=(x%p+p)%p;
return x;
}
ll Mul(ll n,ll pi,ll pk){
if(!n) return 1ll;
ll ans=1ll;
for(ll i=2;i<=pk;i++)
if(i%pi) ans=ans*i%pk;
ans=quick_mod(ans,n/pk,pk);
for(ll i=2;i<=n%pk;i++){
if(i%pi) ans=ans*i%pk;
}
return ans*Mul(n/pi,pi,pk)%pk;
}
ll exlucas(ll n,ll m,ll p,ll pi,ll pk){
if(m>n) return 0ll;
ll a=Mul(n,pi,pk),b=Mul(m,pi,pk),c=Mul(n-m,pi,pk);
ll k=0ll,ans=0ll;
for(ll i=n;i;i/=pi) k+=i/pi;
for(ll i=m;i;i/=pi) k-=i/pi;
for(ll i=n-m;i;i/=pi) k-=i/pi;
ans=a*inv(b,pk)%pk*inv(c,pk)%pk*quick_mod(pi,k,pk)%pk;
return ans*(p/pk)%p*inv(p/pk,pk)%p; //中国剩余定理 a[i]*M*x 余数*其他个个素数的乘积*x
}
int main()
{
ll n,m,p,ans=0;
while(cin>>n>>m>>p){
for(ll x=p,i=2;i<=p;i++){
if(x%i==0){
ll pk=1ll;
while(x%i==0) pk*=i,x/=i;
ans=(ans+exlucas(n,m,p,i,pk))%p;
}
}
cout<
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
const int MAXLEN = 1000005;
const int MAXNUM = 35;
int strnum=0; //字符串的数量
//正序和逆序的字符串
string s1, s2;
//结果
int result[MAXNUM] = { 0 };
//进制数
ll p = 10000019;
//mod
ll mod = 1000000007;
//H数组,H[i]表示字符串前i个字符的子串的hash值
ll H1[MAXLEN] = { 0 }, H2[MAXLEN] = { 0 };
//powp[i]表示p的i次方
ll powp[MAXLEN] = { 0 };
//计算字符串的H数组
void calH(ll* H,string& str) {
H[0] = str[0];
for (int i = 1; i < str.size(); i++) {
H[i] = (H[i - 1] * p + str[i]) % mod;
}
}
//打表,预先求出p的幂次
void getpowp() {
powp[0] = 1;
for (int i = 1; i < MAXLEN; i++) {
powp[i] = (powp[i - 1] * p)%mod;
}
}
//计算子串的哈希值
ll calsubH(ll* H,int i,int j){
//对i为0的情况特殊处理
if (i == 0)
return H[j];
else
return ((H[j] - H[i - 1] * powp[j - i + 1]) % mod + mod) % mod;
}
//比较两个子串是否相等
bool cmp(int i1,int j1,int i2,int j2) {
return calsubH(H1, i1, j1) == calsubH(H2, i2, j2);
}
//对字符串进行预处理,每两个字符之间插入一个'#'
void initstring(string& tmp,int& len) {
len = 2 * len - 1;
char* ch = new char[len + 1];
for (int i = 0; i < len; i++) {
if (i % 2 == 0) ch[i] = tmp[i / 2];
else ch[i] = '#';
}
ch[len] = '\0';
tmp = string(ch);
}
//计算以第i个字符为中心时,回文子串的最大长度
//字符串s1,字符串s2为其反序
int calbyi(int i,int len) {
//搜索区间的最小值、最大值
int lb = 0, rb = min(i, len - i-1);
//字串的半径(不包括中心点),注意必须初始化应对i=0的情况
int k=0;
//使用二分法求解
while (rb > lb) {
//注意半径要大于等于1,否则会在第一个分支中死循环
k = (lb + rb) / 2+1;
//正、反序字串中要比较的子串的开始位置
int b1 = i - k, b2 = len - k - (i + 1);
//判断子串哈希值是否相等
if (cmp(b1,b1+k-1,b2,b2+k-1)) {
//以i为中心,k为半径的子串是回文子串,可以向两边拓展(用二分的方法)
//所以修改区间的最小值,表示半径最少有k个字符
lb = k;
}
else {
//以i为中心,k为半径的子串不是回文子串,所以向中心收缩半径
//修改区间的最大值,表示半径要小于k个字符
rb = k - 1;
}
}
//求除掉'#'后的回文子串的长度,注意这里半径不能用k,因为上面退出循环时可能k的值大于正确半径
//要根据中心字符的类型来判断
//中心为'#',回文子串为偶数长度
if (s1[i] == '#') {
return ((lb + 1) / 2) * 2;
}
//中心为英文字符,回文串为奇数长度
else{
return 2*(lb/2) + 1;
}
}
//计算字符串s1的最长回文字串长度
int cal(int len) {
int maxlen=1; //回文串的最大长度
//遍历所有点,将其作为中心点求解
for (int i = 0; i < len; i++) {
maxlen = max(calbyi(i,len), maxlen);
}
return maxlen;
}
int main(void) {
ios::sync_with_stdio(false);
getpowp(); //打表
//给s1,s2预留空间来优化
s1.reserve(MAXLEN);
s2.reserve(MAXLEN);
//对所有字符串求解其最长回文子串长度
string inputstr;
int strnum = 0;
int len = 0;
while(true) {
getline(cin, s1);
if (s1 == "END") break;
//原始字符串和反序字符串
len = s1.size();
initstring(s1,len); //给字符之间插入'#'
s2 = s1;
reverse(s2.begin(), s2.end());
//计算两个字符串的H数组
calH(H1, s1);
calH(H2, s2);
//求解
result[++strnum]=cal(len);
}
//输出结果
for (int i = 1; i <= strnum; i++) {
cout << "Case " << i << ": " << result[i] << endl;
}
}
尼姆博弈模型,大致上是这样的:
有3堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取1个,多者不限(但不能超过一堆),最后取光者得胜。
所以取到(0,0,0,0)就获胜了 ---- 异或和不等零 先手必胜
/*一般来说,如果可以在 O(1) 内从 [l,r] 的答案转移到 [l-1,r] 、 [l+1,r] 、 [l,r-1] 、 [l,r+1] 这四个与之紧邻的区间的答案,则可以考虑使用莫队
转移分为两种情况,往区间里添数,或者往区间里删数,所以可以写成两个函数:del() , add()
*/
int ll,rr,bs;
lll res=0;
struct node{
int l,r;
int id;
}p[N];
bool cmp(node a,node b){
if(a.l/bs == b.l/bs) return a.r < b.r;
return a.l < b.l;
}
lll cal(lll x){
return 1ll*x*(x-1)/2;
}
void del(int x){
cnt[x&1][a[x]]--;
res -= (cnt[x&1][a[x]]);
}
void add(int x){
res += (cnt[x&1][a[x]]);
cnt[x&1][a[x]]++;
}
void slove(int i){
while(ll < p[i].l) del(ll++);
while(ll > p[i].l) add(--ll);
while(rr < p[i].r) add(++rr);
while(rr > p[i].r) del(rr--);
ans[p[i].id] = cal(p[i].r - p[i].l + 1) - res;
}
signed main(){
// ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
scanf("%lld%lld", &n, &q);
bs = sqrt(n);
for(int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
a[i]--;
a[i] = a[i] ^ a[i-1];
}
for(int i = 1; i <= q; i++){
scanf("%lld%lld", &p[i].l, &p[i].r);
p[i].l--; //本题用的是异或和的前缀和 所以求[l,r]区间时 是用到 [l-1,r]
p[i].id = i;
}
sort(p + 1, p + 1 + q, cmp);
ll = 1, rr = 0;
for(int i = 1; i <= q; i++){
slove(i);
}
for(int i = 1; i <= q; i++)
printf("%lld\n",ans[i]);
return 0;
}
/*
权值线段树一般用于维护一段区间的数出现的次数,从它的定义来看,它可以快速计算出一段区间的数的出现次数。
在实际应用中,我们使用权值线段树查询区间第K大的值。
以数的大小为区间 数x要在[1,n]内
tree[rt] 插入数x 找到x在树中位置rt 次数数组tree[rt]++
*/
//单点更新
//类似基础线段树,递归到叶子节点+1然后回溯
void add(int l, int r, int rt, int x){
if (l == r) tree[rt]++;
else{
int mid = (l + r) >> 1;
if (x <= mid) add(l, mid, rt << 1, x);
else add(mid + 1, r, rt << 1 | 1, x);
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
}
//查询第K大
int query_kth(int pos, int l, int r, int k){ //如果K比右儿子大,就说明第K大的数在左子树中。然后,K要减去右子节点的值。
if(l == r) return l;
int mid = (l + r) >> 1, right = tree[pos << 1 | 1];
if(k <= right) return query(pos << 1 | 1, mid + 1, r, k);
else return query(pos << 1, l, mid, k - right);
}
//查询第K小
int query_kth(int pos, int l, int r, int k){
if(l == r) return l;
int mid = (l + r) >> 1, left = tree[pos << 1];
if(k <= left) return query(pos << 1, l, mid, k - left);
else return query(pos << 1 | 1, mid + 1, r, k);
}
//查询某个数出现次数
int find(int l, int r, int v, int x){
if (l == r) return tree[v];
else{
int mid = (l + r) >> 1;
if (x <= mid) return find(l, mid, v << 1, x);
else return find(mid + 1, r, v << 1 | 1, x);
}
}
//查询一段区间数出现的次数
int find(int l, int r, int v, int x, int y){
if (l == x && r == y) return tree[v];
else{
int mid = (l + r) >> 1;
if (y <= mid) return find(l, mid, v << 1, x, y);
else if (x > mid) return find(mid + 1, r, v << 1 | 1, x, y);
else return find(l, mid, v << 1, x, mid) + find(mid + 1, r, v << 1 | 1, mid + 1, y);
}
}
//区间离散化
int get_discretization(){
for (int i = 1; i <= n; ++i) a[i] = read(), b[i] = a[i]; //读入数据
sort(b + 1, b + n + 1);
int len = unique(b + 1, b + n + 1) - b - 1;
for (int i = 1; i <= n; ++i){
int pos = lower_bound(b + 1, b + len + 1, a[i]) - b;
a[i] = pos;
} //离散化
}
1.len[i]表示编号为i的节点表示的回文串的长度(一个节点表示一个回文串)
2.next[i][c]表示编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号(和字典树类似)。
3.fail[i]表示节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串(和AC自动机类似)。
4.cnt[i]表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的)
5.num[i]表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数。
6.last指向新添加一个字母后所形成的最长回文串表示的节点。
7.S[i]表示第i次添加的字符(一开始设S[0] = -1(可以是任意一个在串S中不会出现的字符))。
8.p表示添加的节点个数。
9.n表示添加的字符个数。
map< pair ,int> mp,ct;
int has1[M],has2[M];
int bas1[M],bas2[M];
int p1,p2;
const int mod1=3145739;//如有误差手动修改
const int mod2=6291469;
void init_base(){
p1=2333;//如有误差手动修改
p2=17;
bas1[0]=bas2[0]=1;
// MXN=3e5+7
for(int i=1;i= 0 ; -- i ) cnt[fail[i]] += cnt[i] ;
//父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!
}
} ;