abc272g摩尔投票
给定一个长度为 n的序列 , 序列中每一个数互不相同, 这个时候想要选择一个数m使得 all数mod m之后, 存在绝对众数.(数量占 一半以上)
1随机化思想
a[i]=ans+k1*mod
a[j]=ans+k2*mod
所以rand找i和j求差值,然后枚举m|abs(ai-aj)
check代价是On
2摩尔投票
算法笔记戳
例题,求区间绝对众数和求个数大于n/3的众数
class Solution {
public:
vector<int> majorityElement(vector<int>& nums) {
int n=nums.size();
int a=0,b=0,x=0,y=0;
for(auto i:nums){
if(a==i&&x)x++;
else if(b==i&&y)y++;
else if(!x)a=i,x++;
else if(!y)b=i,y++;
else x--,y--;
}
vector<int>v;
x=0,y=0;
for(auto t:nums){
if(t==a)x++;
if(t==b)y++;
}
if(x>n/3)v.push_back(a);
if(y>n/3&&b!=a)v.push_back(b);
return v;
}
};
cf169div2E
#include<bits/stdc++.h>
// #define int long long
#define ls u<<1
#define rs u<<1|1
using namespace std;
const int N=1e5+10;
int n,tr[N],dep[N],dfn[N],m,op,u,d,x,sz[N];
int a[N*4],idx,lazy[N*4];
vector<int>g[N];
void dfs(int u,int fa=0){
dep[u]=dep[fa]+1;
dfn[u]=++idx;
sz[u]=1;
for(auto j:g[u]){
if(j==fa)continue;
dfs(j,u);
sz[u]+=sz[j];
}
}
void add(int x,int c){
for(int i=x;i<=n;i+=i&-i)tr[i]+=c;
}
int sum(int x){
int ans=0;
for(int i=x;i;i-=i&-i)ans+=tr[i];
return ans;
}
void pushdown(int u){
int &x=lazy[u];
if(x==0)return;
lazy[ls]+=x,a[ls]+=x;
lazy[rs]+=x,a[rs]+=x;
lazy[u]=0;
}
void modify(int u,int ql,int qr,int v,int l=1,int r=n){
if(ql>qr)return;
if(ql<=l&&r<=qr){
a[u]+=v;
lazy[u]+=v;
return;
}
if(ql>r||qr<l)return;
pushdown(u);
int mid=l+r>>1;
modify(ls,ql,qr,v,l,mid);
modify(rs,ql,qr,v,mid+1,r);
}
int query(int u,int x,int l=1,int r=n){
if(l==r)return a[u];
int mid=l+r>>1;
pushdown(u);
if(x<=mid)return query(ls,x,l,mid);
return query(rs,x,mid+1,r);
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<n;i++){
int a,b;
cin>>a>>b;
g[a].push_back(b);
g[b].push_back(a);
}
dfs(1);
while(m--){
cin>>op;
if(op==0){
cin>>u>>x>>d;
if(u==1){add(d+1,x);continue;}
if(d+1<dep[u])modify(1,dfn[u]-d,min(dfn[u]+d,dfn[u]+sz[u]-1),x);
else{
add(d-dep[u]+2,x);
int l=d-dep[u]+3;
//dfn[u]-dep[u]=ans-l
//ans=dfn[u]-dep[u]+l
int r=min(dfn[u]+d,dfn[u]+sz[u]-1);
modify(1,dfn[u]-dep[u]+l,r,x);
}
}
else{
cin>>u;
cout<<sum(n)-sum(dep[u]-1)+query(1,dfn[u])<<'\n';
}
}
}
edu 64 D
树形dp计数
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10,M=2*N;
//不存在10这样的序列
int f[N][4],n,ans;
/*
0 00
1 01
2 10
3 11
*/
int h[N],e[M],ne[M],idx,w[M];
void add(int a,int b,int c){
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int fa=0){
int a[4];
memset(a,0,sizeof a);
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
if(j==fa)continue;
dfs(j,u);
if(w[i]==0){
a[0]=f[j][0]+1;
a[1]=f[j][1]+f[j][3];
a[2]=0;
a[3]=0;
}
else{
a[0]=0;
a[1]=0;
a[2]=f[j][2]+f[j][0];
a[3]=f[j][3]+1;
}
//答案跨越u节点,在两颗子树之间
//00
ans+=a[0]*f[u][0]*2;
//01
ans+=a[0]*f[u][1]+a[0]*f[u][3]+a[1]*f[u][0];
//10
ans+=a[2]*f[u][3]+a[3]*f[u][2]+a[3]*f[u][0];
//11
ans+=a[3]*f[u][3]*2;
//答案经过u节点,在一棵子树内
ans+=a[0]*2+a[1]+a[2]+a[3]*2;
for(int i=0;i<4;i++)f[u][i]+=a[i];
}
//答案经过u节点,在一棵子树内
// ans+=2*f[u][0]+f[u][1]+f[u][2]+2*f[u][3];
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
memset(h,-1,sizeof h);
for(int i=1;i<n;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
dfs(1);
cout<<ans;
}
并查集组合数
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int n,p[2][N],sz[2][N],ans;
int find(int o,int x){
if(p[o][x]==x)return x;
return p[o][x]=find(o,p[o][x]);
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)p[0][i]=p[1][i]=i,sz[0][i]=sz[1][i]=1;
for(int i=1;i<n;i++){
int a,b,c;
cin>>a>>b>>c;
a=find(c,a),b=find(c,b);
if(a!=b){
p[c][a]=b;
sz[c][b]+=sz[c][a];
}
}
for(int i=1;i<=n;i++){
int a=find(0,i);
int b=find(1,i);
ans+=(sz[0][a]-1)*(sz[1][b]-1);
if(a==i)ans+=sz[0][a]*(sz[0][a]-1);
if(b==i)ans+=sz[1][b]*(sz[1][b]-1);
}
cout<<ans;
}
E. Special Segments of Permutation
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int n,a[N],ans;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=2;i<n;i++){
set<int>S;
if(a[i-1]>a[i]||a[i+1]>a[i])continue;
for(int j=i-1;j>=1;j--){
if(a[j]>a[i])break;
S.insert(a[j]);
}
for(int j=i+1;j<=n;j++){
if(a[j]>a[i])break;
if(S.count(a[i]-a[j]))ans++;
}
}
cout<<ans;
}
概率dp
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
const int N=5050;
int n,x,ans,f[N][N],sum[N][N],inv[N],s[N];
//f[i][j]表示拿了j张牌且最后一次拿到了i的概率
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>x;
s[x]++;
}
inv[0]=inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=(mod-mod/i*inv[mod%i]%mod)%mod;
sum[0][0]=sum[1][0]=1;
for(int i=1;i<=n;i++){//枚举以i为结束牌
for(int j=1;j<=i;j++){//枚举拿了多少张牌
f[i][j]=sum[(i-1)&1][j-1]*s[i]%mod*inv[n-j+1]%mod;
ans+=f[i][j]*(s[i]-1)%mod*inv[n-j]%mod;
ans%=mod;
sum[i&1][j]=(sum[(i-1)&1][j]+f[i][j])%mod;
}
}
cout<<ans;
}
子集dp牛客练习赛E
#include<bits/stdc++.h>
using namespace std;
const int N=24,M=1<<N;
int n,f[M],a[100010];
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
int x=0;
for(int j=i;j<=n;j++){
if(x&a[j])break;
x|=a[j];
f[x]=x;
}
}
int m=M-1;
for(int i=0;i<=m;i++){
for(int j=0;j<=23;j++){
if(i>>j&1)f[i]=max(f[i],f[i-(1<<j)]);
}
}
int ans=0;
for(int i=0;i<=m;i++)ans=max(ans,f[i]+f[m^i]);
cout<<ans;
}
牛客练习赛32C矩阵快速幂
#include<bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
int A[4][4]={
1,1,0,0,
1,0,0,0,
1,0,1,1,
0,0,1,0
};
struct node{
int a[4][4];
node(){memset(a,0,sizeof a);}
void init(){memcpy(a,A,sizeof a);}
node operator*(const node&B)const{
auto &b=B.a;
node C;
auto &c=C.a;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
for(int k=0;k<4;k++){
c[i][j]+=a[i][k]*b[k][j]%mod;
c[i][j]=(c[i][j]%mod+mod)%mod;
}
}
}
return C;
}
node qpow(int b){
node ans;ans.init();b--;
node A;memcpy(A.a,a,sizeof a);
while(b){
if(b&1)ans=ans*A;
b/=2;
A=A*A;
}
return ans;
}
}a,ans;
int n;
void pr(node A){
for(int i=0;i<4;i++)cout<<A.a[0][i]<<" ";
cout<<'\n';
}
signed main(){
cin>>n;
node t;
t.a[0][0]=0;
t.a[0][1]=0;
t.a[0][2]=1;
t.a[0][3]=0;
node A;A.init();
// pr(A);
A=A.qpow(n);
// pr(A);
t=t*A;
// pr(t);
cout<<t.a[0][1];
}
牛客练习赛80C
可以矩阵快速幂来写,记得封装矩阵乘法运算的时候要memset(c.a,0,sizeof c.a)
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=100019;
struct node{
int a[10][10];
void init(){
memset(a,0,sizeof a);
for(int j=1;j<=9;j++)a[1][j]=1;
}
node(){
memset(a,0,sizeof a);
for(int i=1;i<=9;i++){
for(int j=1;j<=i;j++){
a[i][j]=1;
}
}
}
node operator*(const node&b)const{
node c;
memset(c.a,0,sizeof c.a);
for(int i=1;i<=9;i++){
for(int j=1;j<=9;j++){
for(int k=1;k<=9;k++){
c.a[i][j]+=a[i][k]*b.a[k][j];
c.a[i][j]%=mod;
}
}
}
return c;
}
void pr(){
for(int i=1;i<=9;i++){
for(int j=1;j<=9;j++)cout<<a[i][j]<<" ";
cout<<'\n';
}
cout<<"****************************"<<'\n';
}
}A,E;
node qpow(node a,int b){
node ans;
while(b){
if(b&1)ans=ans*a;
b/=2;
a=a*a;
}
return ans;
}
int n;
signed main(){
cin>>n;
A.init();
A=A*qpow(E,n-1);
cout<<A.a[1][1];
}