21杭电多校第二场
A
签到题,对于一个正方体,有\(8\)种顶点均在正方体顶点上满足条件的正三角形
显然\(Ans=\sum\limits_{i=1}^{n-1}8i^3=8(\frac{n(n-1)}{2})^2=2(n-1)n\)
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 1000000007
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ll n,inv2;
ll qp(ll x,ll t,ll res=1)
{
for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;
}
int main()
{
inv2=qp(2,MOD-2);ll ans;rep(T,1,read())
{
n=read()%MOD;n=mns(n,1);ans=mul(n,n+1);
ans=mul(ans,ans);ans=mul(ans,2);printf("%d\n",ans);
}
}
B
树链剖分维护二次函数,每次添加都是添加一段二次函数
平移后变成\(ax^2+bx+c\)的形式,其中\(x\)为线段树的横坐标,这样\(a,b,c\)可加,能直接维护
每次单点查询得到答案
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,nxt[MAXN<<1],fst[MAXN],to[MAXN<<1],cnt,val[MAXN];
int sz[MAXN],dep[MAXN],fa[MAXN],hvs[MAXN],bl[MAXN],in[MAXN],tot;
void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
void dfs(int x,int pa)
{
sz[x]=1,fa[x]=pa;
ren if(to[i]^pa)
{
dep[to[i]]=dep[x]+1;dfs(to[i],x);
sz[x]+=sz[to[i]],hvs[x]=sz[to[i]]>sz[hvs[x]]?to[i]:hvs[x];
}
}
void Dfs(int x,int anc)
{
bl[x]=anc,in[x]=++tot;if(!hvs[x]) return ;Dfs(hvs[x],anc);
ren if(to[i]^fa[x]&&to[i]^hvs[x]) Dfs(to[i],to[i]);
}
ll taga[MAXN<<2],tagb[MAXN<<2],tagc[MAXN<<2];
void build(int k,int l,int r)
{
taga[k]=tagb[k]=tagc[k]=0;if(l==r) return ;
int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
void pshd(int k)
{
taga[k<<1]+=taga[k],taga[k<<1|1]+=taga[k];
tagb[k<<1]+=tagb[k],tagb[k<<1|1]+=tagb[k];
tagc[k<<1]+=tagc[k],tagc[k<<1|1]+=tagc[k];
taga[k]=tagb[k]=tagc[k]=0LL;
}
void mdf(int k,int l,int r,int a,int b,ll A,ll B,ll C)
{
if(a<=l&&r<=b) {taga[k]+=A,tagb[k]+=B,tagc[k]+=C;return ;}
int mid=l+r>>1;if(taga[k]!=0||tagb[k]!=0||tagc[k]!=0) pshd(k);
if(a<=mid) mdf(k<<1,l,mid,a,b,A,B,C);
if(b>mid) mdf(k<<1|1,mid+1,r,a,b,A,B,C);
}
ll query(int k,int l,int r,int x)
{
if(l==r) return taga[k]*x*x+tagb[k]*x+tagc[k];int mid=l+r>>1;
if(taga[k]!=0||tagb[k]!=0||tagc[k]!=0) pshd(k);
return x<=mid?query(k<<1,l,mid,x):query(k<<1|1,mid+1,r,x);
}
inline int lca(int a,int b)
{
for(;bl[a]!=bl[b];a=fa[bl[a]])
if(dep[bl[a]]<dep[bl[b]]) swap(a,b);
if(in[a]>in[b]) swap(a,b);return a;
}
inline ll sqr(ll x){return x*x;}
void work(int a,int b)
{
int z=lca(a,b),l=0,r=0,tmp=dep[a]+dep[b]-2*dep[z]+1;
mdf(1,1,n,in[z],in[z],0,0,sqr(dep[a]-dep[z]+1));
for(;bl[a]!=bl[z];a=fa[bl[a]])
{
l=r+1,r+=dep[a]-dep[bl[a]]+1;
mdf(1,1,n,in[bl[a]],in[a],1,-2LL*(in[a]+l),sqr(in[a]+l));
}
l=r+1,r+=dep[a]-dep[z];
if(in[a]>in[z]) mdf(1,1,n,in[z]+1,in[a],1,-2LL*(in[a]+l),sqr(in[a]+l));
l=tmp+1;
for(;bl[b]!=bl[z];b=fa[bl[b]])
{
r=l-1,l-=dep[b]-dep[bl[b]]+1;
mdf(1,1,n,in[bl[b]],in[b],1,2LL*(r-in[b]),sqr(in[b]-r));
}
r=l-1,l-=dep[b]-dep[z];
if(in[b]>in[z]) mdf(1,1,n,in[z]+1,in[b],1,2LL*(r-in[b]),sqr(in[b]-r));
}
inline ll solve(int a){return query(1,1,n,in[a]);}
int main()
{
n=read();int a,b,c;
rep(i,2,n) a=read(),b=read(),add(a,b),add(b,a);
int q=read();dfs(1,0);Dfs(1,1);
build(1,1,n);
while(q--)
{
c=read(),a=read();if(c&1) b=read();
if(c&1) work(a,b);else printf("%lld\n",solve(a));
}
}
C
先处理出从\(z\)出发的最短路,若\(dis_x\neq dis_y\)则显然胜负已分
对于\(dis_x=dis_y\)的情况,若均不能到达则为平局
否则设\(f[x][y][k]\)表示\(Alice\)在\(x\)点,\(Bob\)在\(y\)点,现在该谁走的胜负情况
\(DP\)即可,二者均只会选择对自己最优的后继状态,这个转移只会沿着最短路边转移,状态很少
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,f[1010][1010][2],dis[1010],q[1010],hd,tl,z;
vector<int> G[1010],H[1010];vector<pii> del;
int dp(int x,int y,int k)
{
if(!k&&(x==z||y==z))
{
if(x==z&&y==z) return 2;
else return x==z?1:3;
}
if(f[x][y][k]) return f[x][y][k];
if(!k)
{
f[x][y][k]=3;for(auto i:H[x]) if(i!=y||i==z)
f[x][y][k]=min(f[x][y][k],dp(i,y,k^1));
}
else
{
f[x][y][k]=1;for(auto i:H[y]) if(i!=x||i==z)
f[x][y][k]=max(f[x][y][k],dp(x,i,k^1));
}
del.pb({x,y});return f[x][y][k];
}
int main()
{
int x,y,t,a,b;rep(T,1,read())
{
n=read(),m=read(),x=read(),y=read(),z=read();
rep(i,1,n) dis[i]=inf,G[i].clear();
rep(i,1,m) a=read(),b=read(),G[a].pb(b),G[b].pb(a);
q[hd=tl=1]=z,dis[z]=0;
while(hd<=tl)
{
t=q[hd++];for(auto v:G[t])
if(dis[v]==inf) dis[v]=dis[t]+1,q[++tl]=v;
}
if(dis[x]!=dis[y]) {puts(dis[x]<dis[y]?"1":"3");continue;}
if(dis[x]==inf) {puts("2");continue;}
rep(i,1,n) H[i].clear();
rep(i,1,n) for(auto v:G[i]) if(dis[v]==dis[i]+1) H[v].pb(i);
printf("%d\n",dp(x,y,0));for(auto x:del) f[x.fi][x.se][0]=f[x.fi][x.se][1]=0;
}
}
D
对于每个查询先不考虑异或的限制,相当于求有多少个\(i\)满足\(l\le i\le r\)且\(las_i< l\)
令每个点坐标为\((las_i,i)\),可以用扫描线树状数组解决
而对于异或的限制,在\(trie\)树上查询,可以得到一些节点,只有经过这些节点的值对于这次查询才有意义
因此我们可以把询问放到每个\(trie\)树的节点上,插入值时同样把这个点的坐标加入经过的所有节点
这样对于\(trie\)树的所有节点都扫描线二位数点就可以解决问题
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,g[MAXN],c[MAXN],ans[MAXN],res;
int tr[MAXN*18][2],tot,las[MAXN],pos[MAXN];
void mdf(int x,int w){for(;x<=n;x+=x&-x) c[x]+=w;}
int query(int x,int res=0){for(;x;x-=x&-x) res+=c[x];return res;}
struct node{int l,r,x,id;};
bool operator < (node &a,node &b)
{
if(a.x!=b.x) return a.x<b.x;
if(a.r!=b.r) return a.r<b.r;
return a.id<b.id;
}
vector<node> vec[MAXN*18];
inline void ins(int x,int id)
{
int p=0,t;dwn(i,17,0)
{
t=(x>>i)&1;if(!tr[p][t]) tr[p][t]=++tot;
p=tr[p][t];vec[p].pb({0,id,las[id],0});
}
}
inline void insq(int l,int r,int a,int b,int id)
{
int t,res=0,p=0,g;
dwn(i,17,0)
{
t=(a>>i)&1,g=(b>>i)&1;
if(g)
{
if(tr[p][t]) {vec[tr[p][t]].pb({l,r,l-1,id});}
if(tr[p][t^1]) p=tr[p][1^t];
else {p=-1;break;}
}
else
{
if(tr[p][t]) p=tr[p][t];
else {p=-1;break;}
}
}
if(~p) vec[p].pb({l,r,l-1,id});
}
int main()
{
n=read();rep(i,1,n) g[i]=read(),pos[i]=-1;
rep(i,1,n) las[i]=pos[g[i]],pos[g[i]]=i;
rep(i,1,n) ins(g[i],i);
m=read();int l,r,a,b;
rep(i,1,m) {l=read(),r=read(),a=read(),b=read();insq(l,r,a,b,i);}
rep(i,1,tot)
{
sort(vec[i].begin(),vec[i].end());
for(auto x:vec[i])
if(!x.id) mdf(x.r,1);
else ans[x.id]+=query(x.r)-query(x.l-1);
for(auto x:vec[i]) if(!x.id) mdf(x.r,-1);
}
rep(i,1,m) printf("%d\n",ans[i]);
}
(赛时直接莫队可过
E
签到题,只有最前面连续若干个相同的\(k\)个相同字符可以有不同方案,答案为\(2^{k-1}\)
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 1000000007
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,ans;char s[MAXN];
int main()
{
rep(T,1,read())
{
n=read();scanf("%s",s+1);ans=1;
rep(i,2,n) if(s[i]==s[i-1]) ans=mul(ans,2);else break;
printf("%d\n",ans);
}
}
F
由于调和级数复杂度为\(nlogn\),因此对每个\(p\)可以分别计算
考虑\(FWT\)的过程,已知\(A[0],A[1],A[2]\);\(B[0],B[1],B[2]\)
由题目规定位运算的定义可知
\(C[0]=A[0]B[0]\)
\(C[2]=A[2]B[0]+A[0]B[2]+A[2]B[2]\\\quad \ \ \ =(A[0]+A[2])(B[0]+B[2])-A[0]B[0]\)
\(C[1]=A[0]B[1]+A[1]B[0]+A[1]B[1]+A[1]B[2]+A[2]B[1]\\\quad \ \ \ =(A[0]+A[1]+A[2])(B[0]+B[1]+B[2])-(A[0]+A[2])(B[0]+B[2])\)
则可令\(fwt\)过程为\(\{a_0,a_1,a_2\}\rightarrow\{a_0,a_0+a_1+a_2,a_0+a_2\}\)
令\(ifwt\)过程为\(\{a_0,a_1,a_2\}\rightarrow\{a_0,a_1-a_2,a_2-a_0\}\)
每次\(fwt\)后再按题意计算即可
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 600100
#define MOD 1000000007
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) ((a-(b))%MOD+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,a[MAXN],b[MAXN],c[MAXN],ans,A[MAXN],B[MAXN];
void trans(int &a,int &b,int &c)
{
c=pls(c,a),b=pls(b,c);
}
void itrans(int &a,int &b,int &c)
{
b=mns(b,c),c=mns(c,a);
}
void fwt(int *a,int n,int t)
{
for(int i=1;i<n;i*=3) for(int j=0;j<n;j+=i*3) rep(k,0,i-1)
if(!t) trans(a[j+k],a[j+k+i],a[j+k+2*i]);
else itrans(a[j+k],a[j+k+i],a[j+k+2*i]);
}
void solve(int *a,int *b,int n)
{
fwt(a,n,0);fwt(b,n,0);
rep(i,0,n-1) a[i]=mul(a[i],b[i]);fwt(a,n,1);
}
int main()
{
n=read();
rep(i,1,n) scanf("%d",&a[i]);
rep(i,1,n) scanf("%d",&b[i]);
rep(i,1,n) scanf("%d",&c[i]);
rep(p,1,n)
{
int t=n/p,pw=1,lim=1;rep(i,1,t) A[i]=a[i],B[i]=b[i];
while(lim<=t) lim*=3;solve(A,B,lim);
rep(i,1,lim) pw=mul(pw,c[p]),ans=pls(ans,mul(pw,A[i]));
rep(i,1,lim) A[i]=B[i]=0;
}
printf("%d\n",ans);
}
G
很容易想到线段树维护矩阵,朴素的想法是维护一个\(6\times 6\)的矩阵,但事实上并不需要
考虑二三操作,相当于对行向量\((a,b)\)进行矩阵乘一个矩阵,即乘以\(\begin{pmatrix}3&3\\2&-2\end{pmatrix}\)或\(\begin{pmatrix}0 &1\\1&0\end{pmatrix}\)
对于线段树每个节点维护\(\sum a_i,\sum b_i,\sum a_i^2,\sum b_i^2,\sum a_ib_i,tag_a,tag_b,tag_m\),其中\(tag_a,tag_b\)表示加法标记,\(tag_m\)表示矩阵乘法的标记
对于加法维护的各项容易推出,考虑乘一个矩阵\(\begin{pmatrix}c&d\\e&f\end{pmatrix}\)的影响
\(\sum a_i\rightarrow c\sum a_i+e\sum b_i\),\(\sum b_i\rightarrow d\sum a_i+f\sum b_i\)
则\(\sum a_ib_i\rightarrow\sum (ca_i+eb_i)(da_i+fb_i)=cd\sum a_i^2+ef\sum b_i^2+(cf+ed)\sum a_ib_i\),由之前维护的值可以转移得到;\(\sum a_i^2,\sum b_i^2\)同理
注意\(tag_a,tag_b\)同样需要变动,优先进行矩阵的\(tag\)运算因此需要将原先存在的加法\(tag\)变为先矩乘之后的值
例如\(ca+eb+tag_a'=c(a+tag_a)+e(b+tag_b)\)即\(tag_a\rightarrow c\ tag_a+e\ tag_b\);\(tag_b\)同理
这样每次\(pushdown\)的时候需要优先进行\(tag_m\)的运算再\(pushdown\)加法\(tag\)
查询普通区间查询\(\sum a_ib_i\)即可
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 200100
#define MOD 1000000007
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b)+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,a[MAXN],b[MAXN];
inline void inc(ll &x,int y){x=pls(x,y);}
struct mat
{
int a[2][2];
mat(){a[0][0]=a[1][1]=1,a[0][1]=a[1][0]=0;}
mat operator *(const mat &x)
{
mat res;
rep(i,0,1) rep(j,0,1)
{
res.a[i][j]=0;rep(k,0,1)
res.a[i][j]=pls(res.a[i][j],mul(a[i][k],x.a[k][j]));
}
return res;
}
}exc,trans,one;
struct node{mat tagm;ll s[2],s2[2],tag[2],ans;}tr[MAXN<<2];
inline void upd(int k)
{
tr[k].ans=pls(tr[k<<1].ans,tr[k<<1|1].ans);
rep(i,0,1) tr[k].s[i]=pls(tr[k<<1].s[i],tr[k<<1|1].s[i]);
rep(i,0,1) tr[k].s2[i]=pls(tr[k<<1].s2[i],tr[k<<1|1].s2[i]);
}
inline ll sqr(ll x){return mul(x,x);}
void build(int k,int l,int r)
{
if(l==r)
{
tr[k].tag[0]=tr[k].tag[1]=0;
tr[k].s[0]=a[l],tr[k].s[1]=b[l];
tr[k].s2[0]=sqr(a[l]);tr[k].s2[1]=sqr(b[l]);
tr[k].ans=mul(a[l],b[l]);
return ;
}
int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
upd(k);
}
inline void Add(int k,int l,int r,int t,int x)
{
if(!x) return ;inc(tr[k].tag[t],x);
inc(tr[k].s2[t],pls(mul(tr[k].s[t],2*x),mul(mul(x,x),r-l+1)));
inc(tr[k].ans,mul(x,tr[k].s[t^1]));
inc(tr[k].s[t],mul(r-l+1,x));
}
inline void Mdf(int k,int l,int r,mat m)
{
tr[k].tagm=tr[k].tagm*m;
int a=m.a[0][0],b=m.a[1][0],c=m.a[0][1],d=m.a[1][1],p,q,tmp;
p=tr[k].s2[0],q=tr[k].s2[1],tmp=tr[k].ans;
tr[k].ans=mul(tr[k].ans,pls(mul(a,d),mul(b,c)));
inc(tr[k].ans,pls(mul(mul(a,c),p),mul(mul(b,d),q)));
tr[k].s2[0]=pls(mul(p,sqr(a)),mul(q,sqr(b)));
inc(tr[k].s2[0],mul(mul(a,b),mul(tmp,2)));
tr[k].s2[1]=pls(mul(p,sqr(c)),mul(q,sqr(d)));
inc(tr[k].s2[1],mul(mul(c,d),mul(tmp,2)));
p=tr[k].s[0],q=tr[k].s[1];
tr[k].s[0]=pls(mul(a,p),mul(b,q));
tr[k].s[1]=pls(mul(c,p),mul(d,q));
p=tr[k].tag[0],q=tr[k].tag[1];
tr[k].tag[0]=pls(mul(a,p),mul(b,q));
tr[k].tag[1]=pls(mul(c,p),mul(d,q));
}
void pshd(int k,int l,int r,int mid)
{
Mdf(k<<1,l,mid,tr[k].tagm);Mdf(k<<1|1,mid+1,r,tr[k].tagm);
rep(i,0,1)
Add(k<<1,l,mid,i,tr[k].tag[i]),
Add(k<<1|1,mid+1,r,i,tr[k].tag[i]);
tr[k].tagm=one;rep(i,0,1) tr[k].tag[i]=0;
}
void add(int k,int l,int r,int a,int b,int t,int x)
{
if(a<=l&&r<=b) {Add(k,l,r,t,x);return ;}
int mid=l+r>>1;pshd(k,l,r,mid);
if(a<=mid) add(k<<1,l,mid,a,b,t,x);
if(b>mid) add(k<<1|1,mid+1,r,a,b,t,x);
upd(k);
}
void mdf(int k,int l,int r,int a,int b,mat x)
{
if(a<=l&&r<=b) {Mdf(k,l,r,x);return ;}
int mid=l+r>>1;pshd(k,l,r,mid);
if(a<=mid) mdf(k<<1,l,mid,a,b,x);
if(b>mid) mdf(k<<1|1,mid+1,r,a,b,x);
upd(k);
}
ll query(int k,int l,int r,int a,int b)
{
if(a<=l&&r<=b) return tr[k].ans;
int mid=l+r>>1;ll res=0;pshd(k,l,r,mid);
if(a<=mid) res=query(k<<1,l,mid,a,b);
if(b>mid) res=pls(query(k<<1|1,mid+1,r,a,b),res);
return res;
}
int main()
{
n=read();rep(i,1,n) a[i]=read(),b[i]=read();
exc.a[0][1]=exc.a[1][0]=1,exc.a[0][0]=exc.a[1][1]=0;
trans.a[0][0]=trans.a[0][1]=3,trans.a[1][0]=2,trans.a[1][1]=MOD-2;
one.a[0][0]=one.a[1][1]=1,one.a[0][1]=one.a[1][0]=0;
build(1,1,n);int l,r,x,t;
rep(Q,1,read())
{
t=read();
if(t==1) {t=read(),l=read(),r=read(),x=read();add(1,1,n,l,r,t,x);}
else
{
l=read(),r=read();
if(t==2) mdf(1,1,n,l,r,trans);
else if(t==3) mdf(1,1,n,l,r,exc);
else printf("%lld\n",query(1,1,n,l,r));
}
}
}
H
简单\(dp\)组合
先\(dp\)出每门课\(i\)花费\(j\)时间最多可以获得多少分
再设\(dp[i][j][k]\)表示前\(i\)门课花了\(j\)时间挂了\(k\)门课获得的最大分数,用之前处理出的数组转移
最后对所有合法答案取\(max\)
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define w first
#define v second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,p,f[55][550],dp[55][550][5],ans;
vector<pii> vec[55];
map<string,int> hsh;
int main()
{
rep(T,1,read())
{
n=read();string s;int a,b;
rep(i,1,n) {cin>>s;hsh[s]=i;}
m=read();rep(i,1,m) {cin>>s;a=read(),b=read();vec[hsh[s]].pb({a,b});}
m=read(),p=read();
rep(i,1,n) {f[i][0]=0;rep(j,1,m) f[i][j]=-inf/2;}
rep(i,1,n) for(auto x:vec[i])
dwn(j,m,x.v) f[i][j]=min(max(f[i][j],f[i][j-x.v]+x.w),100);
rep(i,0,n) rep(j,0,m) rep(k,0,p) dp[i][j][k]=-inf/2;
dp[0][0][0]=0;
rep(i,1,n) rep(j,0,m) rep(k,0,j) rep(t,0,p)
if(f[i][j-k]>=60) dp[i][j][t]=max(dp[i][j][t],dp[i-1][k][t]+f[i][j-k]);
else if(t) dp[i][j][t]=max(dp[i][j][t],dp[i-1][k][t-1]+f[i][j-k]);
ans=-1;rep(i,0,m) rep(j,0,p) ans=max(ans,dp[n][i][j]);
printf("%d\n",ans);hsh.clear();rep(i,1,n) vec[i].clear();
}
}
I
先将所有数的平方因子都消去,记录每个数的出现次数
对于一个满足条件的三元组\((i,j,k)\)一定满足以下两种情况之一:
- \(i,j,k\)均不含有\(>\sqrt{M}\)的质因子
- \(i,j,k\)中两个含有\(>\sqrt{M}\)的质因子
第一种情况的三元组不会太多,可以直接爆搜,注意搜索时从大到小枚举质数
第二种可以枚举\([\sqrt{M},M]\)范围内的质数\(p\),再枚举两个\(p\)的倍数,计算第三个较小数统计答案
第二部分复杂度小于\(\int_{\sqrt{M}}^M\ (\frac{M}{x})^2dx=M^2(\frac{1}{\sqrt{M}}-\frac{1}{M})<M\sqrt{M}\)
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-(b)+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int lim=1e5,val=sqrt(lim+0.5);ll ans;
int n,mxp,p[MAXN],tot,ntp[MAXN],mp[MAXN],w[MAXN],g[350][350];
int gcd(int a,int b) {return !b?a:gcd(b,a%b);}
int mem(int n=lim)
{
rep(i,2,n)
{
if(!ntp[i]) p[++tot]=i,mp[i]=i;
rep(j,1,tot) if(i*p[j]>n) break;
else {ntp[i*p[j]]=1,mp[i*p[j]]=p[j];if(i%p[j]==0) break;}
}
mxp=lower_bound(p+1,p+tot+1,val)-p;
rep(i,1,val) rep(j,i,val) g[i][j]=gcd(i,j),g[i][j]=i*j/g[i][j]/g[i][j];
}
void dfs(int x,int a,int b,int c)
{
if(!x)
{
if(a<=b&&b<=c)
{
if(a==1)
{
if(b==1) ans+=(ll)w[1]*(w[1]-1)*(w[1]-2)/6;
else ans+=(ll)w[b]*(w[b]-1)*w[1]/2;
}
else ans+=(ll)w[a]*w[b]*w[c];
}
return ;
}
dfs(x-1,a,b,c);
if(a*p[x]<=lim&&b*p[x]<=lim) dfs(x-1,a*p[x],b*p[x],c);
if(b*p[x]<=lim&&c*p[x]<=lim) dfs(x-1,a,b*p[x],c*p[x]);
if(a*p[x]<=lim&&c*p[x]<=lim) dfs(x-1,a*p[x],b,c*p[x]);
}
int main()
{
mem();int x,tmp,cnt,d;
rep(T,1,read())
{
n=read();Fill(w,0);ans=0;
rep(i,1,n)
{
x=read(),tmp=1;
while(x>1)
{
while(x>1&&x%(mp[x]*mp[x])==0) x/=mp[x],x/=mp[x];
if(x>1&&x%mp[x]==0) tmp*=mp[x],x/=mp[x];
}
w[tmp]++;
}
dfs(mxp,1,1,1);
rep(i,mxp+1,tot) rep(j,1,lim/p[i]) rep(k,j,lim/p[i])
{
if(j==k) ans+=1LL*w[1]*w[j*p[i]]*(w[j*p[i]]-1)/2;
else ans+=1LL*w[j*p[i]]*w[k*p[i]]*w[g[j][k]];
}
printf("%lld\n",ans);
}
}
J
可以发现,最终得到的数列一定是一个长度为\(P-1\)的排列
令这个排列为\(\pi\),排列中第\(i\)个数为\(\pi(i)\),排列的逆序对数为\(n(\pi)\),\(sgn(\pi)=(-1)^{n(\pi)}\)
想要消掉这个取模,考虑对\(sgn(\pi)\)取模,即:
只需要用快速幂判断\(a^\frac{P(P-1)}{2}\ \ (mod\ \ P)\)是否等于\(1\)即可
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) ((__int128)(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ll a,MOD;
ll qp(ll x,ll t,ll res=1)
{
for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);
return res;
}
int main()
{
rep(T,1,read())
{
a=read(),MOD=read();
puts((qp(a,(MOD-1)/2)==1LL)?"0":"1");
}
}
K
若\(i\&j=k\),则说明\(k\)的二进制表示是\(i,j\)的子集,对于一个\(k\)需要考虑所有这样的数
设\(f_i\)表示所有能转移到\(i\)的\(a\)的最大值,则\(f_i=max\{a_j\},i\subseteq j\)
枚举所有显然复杂度过高,可以每次只向减少\(1\)个\(1\)的数转移即\(f_i=max\{f_j\},j=i|(1<<k)\),复杂度\(nlogn\)
又由于\(a,b\)存在负数,因此需要维护\(maxa,mina,maxb,minb\),最后的答案一定可以从这\(2\times2\)种情况中得到
对每个点再求一次后缀\(max\)即为所求
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 300100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,mxa[MAXN],mxb[MAXN],mna[MAXN],mnb[MAXN],t=1;
ll ans[MAXN],res;
int main()
{
rep(T,1,read())
{
n=read();t=1;while((1<<t)<n) t++;
rep(i,0,n-1) {scanf("%d",&mxa[i]);mna[i]=mxa[i];}
rep(i,0,n-1) {scanf("%d",&mxb[i]);mnb[i]=mxb[i];}
dwn(i,n-1,0) rep(j,0,t) if((i>>j)&1)
mxa[i^(1<<j)]=max(mxa[i^(1<<j)],mxa[i]),
mxb[i^(1<<j)]=max(mxb[i^(1<<j)],mxb[i]),
mna[i^(1<<j)]=min(mna[i^(1<<j)],mna[i]),
mnb[i^(1<<j)]=min(mnb[i^(1<<j)],mnb[i]);
rep(i,0,n-1)
ans[i]=max(1LL*mxa[i]*mxb[i],1LL*mxa[i]*mnb[i]),
ans[i]=max(max(1LL*mna[i]*mxb[i],1LL*mna[i]*mnb[i]),ans[i]);
res=ans[n-1];
dwn(i,n-2,0) ans[i]=max(ans[i],ans[i+1]),res=pls(res,ans[i]);
printf("%d\n",(res+MOD)%MOD);
}
}
L
签到题,暴力判断即可
#include<bits/stdc++.h>
#define inf 2139062143
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define MAXN 100100
#define MOD 998244353
#define Fill(a,x) memset(a,x,sizeof(a))
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
#define ren for(int i=fst[x];i;i=nxt[i])
#define pls(a,b) (a+b)%MOD
#define mns(a,b) (a-b+MOD)%MOD
#define mul(a,b) (1LL*(a)*(b))%MOD
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
char s[100100];int n;
int cheq()
{
rep(i,1,n-5)
if(s[i]=='1'&&s[i+1]=='1'&&s[i+2]=='4'&&s[i+3]=='5'&&s[i+4]=='1'&&s[i+5]=='4')
return 1;
return 0;
}
int main()
{
rep(T,1,read())
{
scanf("%s",s+1);n=strlen(s+1);
puts(cheq()?"AAAAAA":"Abuchulaile");
}
}