C-子段乘积
思路:
前缀积 费马小定理 逆元
当p为质数时可以用快速幂求逆元
当p不是质数时,可以用扩展欧几里得算法求逆元
因为a有逆元的充要条件是a与p互质,所以 gcd(a,p)=1
由费马小定理:
∵bp−1≡1(mod p)
∴bp−2=b1(mod p)
∴ba≡a∗bp−2(mod p)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <map>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-10;
const int NINF = 0xc0c0c0c0;
const int INF = 0x3f3f3f3f;
const ll mod = 998244353;
const ll maxn = 1e6 + 5;
int n,k;
ll a[maxn];
ll c[maxn];
ll l[maxn];//用l[]数组来维护中间是否为0
ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1)
res=res*a%mod;
b>>=1;
a=a*a%mod;
}
return res;
}
int main(){
cin>>n>>k;
c[0]=1;
int cnt=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]==0){
c[i]=1;
cnt++;
}
else c[i]=c[i-1]*a[i]%mod;
l[i]=cnt;
}
ll res=0;//这里的res最小值为0 不能设置为NINF 因为下面的情况没考虑0的情况
l[0]=0;
for(int i=k;i<=n;i++){
if(l[i]==l[i-k]&&c[i]*qpow(c[i-k],mod-2)%mod>res){//若l[i]==l[i-k]则说明(i-k+1,i]均非0
res=c[i]*qpow(c[i-k],mod-2)%mod;
}
}
cout<<res;
return 0;
}
D-子段异或
思路:
求前缀异或,并用map数组记录对应值的个数,其中0对应的个数初始化为1。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const ll maxn = 2e5 + 5;
int n;
ll a[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
map<ll,ll>mp;
ll res=0,ans=0;
mp[0]=1;
for(int i=1;i<=n;i++){
cin>>a[i];
ans^=a[i];
res+=mp[ans];//注意这里的顺利 出现一个mp[ans]那么可以增加的字段数量为左侧已有的mp[ans]的数量 则也就是先res+=mp[ans]再mp[ans]++的原因
mp[ans]++;
}
cout<<res;
return 0;
}