省选联测(14~20)
省选联测14 整除#
ps:
我们考虑对两式同时乘以
设
ps: 这里多项式取模其实就是对指数取模。
发现
我们判断
- 若
,则将 减去 ,将 加上 。 - 若
,则将 加上 ,将 减去 。
如果最后剩下的
我们只需要枚举
可以用
code
#include<bits/stdc++.h>
#define int long long
#define mk make_pair
using namespace std;
const int N=1e5+10;
int c[N],a[N];
map<int,int> k,vis;
int n,m;
struct asd{
int x,k;
}st[N];
set<pair<int,int>>s;
int top;
bool check(int x){
int top=0;
while(1){
auto ip=s.begin(),it=s.end();
it--;
int op=0;
while(k[(*it).second]>=x){
op=1;
int sx=it -> first;
int sy=it -> second;
if(!vis[sy]){
vis[sy]=1;
st[++top]={sy,k[sy]};
}
s.erase(mk(k[sy%m],sy%m));
k[sy%m]-=x;
s.insert(mk(k[sy%m],sy%m));
if(!vis[(sy+1)%m]){
vis[(sy+1)%m]=1;
st[++top]={(sy+1)%m,k[(sy+1)%m]};
}
s.erase(mk(k[(sy+1)%m],(sy+1)%m));
k[(sy+1)%m]++;
s.insert(mk(k[(sy+1)%m],(sy+1)%m));
}
while(k[(*ip).second]<=-x){
op=1;
int sy=ip -> second;
if(!vis[sy]){
vis[sy]=1;
st[++top]={sy,k[sy]};
}
s.erase(mk(k[sy%m],sy%m));
k[sy%m]+=x;
s.insert(mk(k[sy%m],sy%m));
if(!vis[(sy+1)%m]){
vis[(sy+1)%m]=1;
st[++top]={(sy+1)%m,k[(sy+1)%m]};
}
s.erase(mk(k[(sy+1)%m],(sy+1)%m));
k[(sy+1)%m]--;
s.insert(mk(k[(sy+1)%m],(sy+1)%m));
}
if(!op) break;
}
auto it=s.begin(),ip=s.end();
ip--;
int sx=(*it).first,sy=(*ip).first;
for(int i=1;i<=top;i++){
int s1=st[i].x,s2=st[i].k;
vis[s1]=0;
s.erase(mk(k[s1],s1));
k[s1]=s2;
s.insert(mk(k[s1],s1));
}
if(sx!=sy) return 0;
else{
if(sx==x-1) return 1;
if(sx==-x+1) return 1;
if(sx==0) return 1;
return 0;
}
}
signed main(){
freopen("div.in","r",stdin);
freopen("div.out","w",stdout);
int T;
scanf("%lld",&T);
while(T--){
scanf("%lld%lld",&n,&m);
k.clear();
s.clear();
int sum=0;
for(int i=0;i<n;i++){
scanf("%lld%lld",&c[i],&a[i]);
sum+=c[i];
}
int mx=0;
int op=0;
for(int i=0;i<n;i++){
s.erase(mk(k[(a[i]+1)%m],(a[i]+1)%m));
k[(a[i]+1)%m]+=c[i];
s.insert(mk(k[(a[i]+1)%m],(a[i]+1)%m));
s.erase(mk(k[a[i]%m],a[i]%m));
k[a[i]%m]-=c[i];
s.insert(mk(k[a[i]%m],a[i]%m));
}
auto it=s.end();
it--;
mx=(*it).first;
if((*it).first==(*s.begin()).first && (*it).first==0){
printf("-1\n");
continue;
}
int ans=0;
if(sum%m==0) ans++;
for(int i=2;i<=mx;i++){
if(check(i)) ans++;
}
printf("%lld\n",ans);
}
}
省选联测14 词典#
ps:
我们考虑对这个建一棵
发现
因为
我们考虑倍增,对于决策点
复杂度
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2*1e7;
const int inf=3e15;
int w[N+5];
int f[N+5];
int ask(int p,int n){
int ans=f[p]+f[n-p];
if(p>1) ans+=w[p];
return ans;
}
int br[N],val[N],ads[N],cnt=0;
int F(int x){
if(x<=N) return f[x];
int pos=lower_bound(br+1,br+cnt+1,x)-br;
return val[pos-1]+ads[pos]*(x-br[pos-1]);
}
int g[N],sumg[N],tp=0;
int W(int x){
int pos=lower_bound(g+1,g+tp+1,x)-g;
if(g[pos]>x) pos--;
return sumg[pos]+(pos-1)*(x-g[pos]+1)+x;
}
int query(int x){
if(x<=N) return f[x];
int l=max(x/3,x-br[cnt]),r=(x+1)/2;
int ans=LONG_LONG_MAX;
while(r-l>2){
int mid1=l+(r-l)/3,mid2=r-(r-l)/3;
int ans1=F(mid1)+F(x-mid1)+W(mid1)+W(x);
int ans2=F(mid2)+F(x-mid2)+W(mid2)+W(x);
if(ans1<=ans2){
r=mid2;
ans=min(ans,ans1);
}
else{
l=mid1;
ans=min(ans,ans2);
}
}
return ans;
}
void init(){
int kl=1;
while(kl<=inf){
g[++tp]=kl;
if(tp>1) sumg[tp]=sumg[tp-1]+(kl-g[tp-1])*(tp-2);
kl*=2;
}
for(int i=1;i<=N;i++) w[i]=w[i-1]+(int)(1+log2(i));
f[1]=1;
int p=1;
for(int i=2;i<=N;i++){
while(p+1<i && ask(p,i)>ask(p+1,i)) p++;
f[i]=ask(p,i)+w[i];
}
int dels=f[N]-f[N-1];
int ed=N;
br[++cnt]=ed,ads[cnt]=dels,val[cnt]=f[ed];
int sum=0;
while(ed<=inf){
sum++;
int stp=ed+1,nex=stp;
dels=query(stp)-F(stp-1);
while(stp<=inf){
nex=stp*3/2;
int tmp=query(nex);
if(tmp-query(nex-1)!=dels) break;
stp=nex;
}
for(int i=50;i>=0;i--){
if(stp+(1ll<<i)<=nex){
int tmp=stp+(1ll<<i);
if(query(tmp)-query(tmp-1)==dels) stp=tmp;
}
}
br[++cnt]=stp,ads[cnt]=dels;
br[cnt]=stp,val[cnt]=query(stp);
ed=stp;
}
}
int write(int x){
if(x<=N) return f[x];
else return F(x);
}
signed main(){
freopen("dictionary.in","r",stdin);
freopen("dictionary.out","w",stdout);
int T;
scanf("%lld",&T);
init();
while(T--){
int n;
scanf("%lld",&n);
printf("%lld\n",write(n));
}
}
省选联测17#
树上的棋局#
首先考虑
我们发现每个点对答案的贡献要么是距离最大值,要么是距离次大值,因为一个节点只有一个父亲。而且最大值对应的点一定是直径的一个端点,且经过直径的中点。那么我们发现,只有根到直径中点的路径上的点最大值才会产生贡献,其它点都是次大值产生贡献。
考虑修改和换根怎么做,我们维护四个值:奇数最大,奇数次大,偶数最大,偶数次大。显然偶数都为
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2*1e5+10;
int head[N],nex[N*2],ver[N*2],tot=0;
void add(int x,int y){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot;
}
int fa[N],siz[N],dfn[N],rk[N],top[N],dep[N],son[N],num=0;
int mx[N],mxx[N],px[N],pxx[N];
int maxdep=(1ll<<50),pot1,pot2;
void dfs_1(int x,int fat){
mx[x]=px[x]=0;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fat) continue;
dfs_1(y,x);
if(mx[x]<mx[y]+1){
mx[x]=mx[y]+1;
px[x]=y;
}
}
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fat || y==px[x]) continue;
if(mxx[x]<mx[y]+1){
mxx[x]=mx[y]+1;
pxx[x]=y;
}
}
}
void dfs_2(int x,int fat){
if(maxdep>mx[x]){
maxdep=mx[x];
pot1=x;
pot2=0;
}
else if(maxdep==mx[x]){
pot2=x;
}
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fat) continue;
int w;
if(pxx[x]!=y) w=mxx[x]+1;
if(px[x]!=y) w=mx[x]+1;
if(mx[y]<w){
mxx[y]=mx[y];
pxx[y]=px[y];
mx[y]=w;
px[y]=x;
}
else if(mxx[y]<w){
mxx[y]=w;
pxx[y]=x;
}
dfs_2(y,x);
}
}
void dfs1(int x,int fat){
fa[x]=fat;
dep[x]=dep[fat]+1;
siz[x]=1;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fat) continue;
dfs1(y,x);
siz[x]+=siz[y];
if(siz[son[x]]<siz[y]) son[x]=y;
}
}
void dfs2(int x,int tp){
top[x]=tp;
dfn[x]=++num;
rk[num]=x;
if(son[x]) dfs2(son[x],tp);
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y!=fa[x] && y!=son[x]) dfs2(y,y);
}
}
int ask_lca(int x,int y){
int fx=top[x],fy=top[y];
while(fx!=fy){
if(dep[fx]>dep[fy]){
x=fa[fx],fx=top[x];
}else{
y=fa[fy],fy=top[y];
}
}
if(dep[x]<dep[y]) return x;
else return y;
}
int ask_dist(int x,int y){
if(!x || !y) return (1ll<<50);
int lca=ask_lca(x,y);
return dep[x]+dep[y]-2*dep[lca];
}
struct Segment{
struct tree{
int l,r,ans0,ans1,cnt0,cnt1,lazy1,lazy2;
}tr[N*4];
void pushup(int p){
tr[p].ans1=tr[p*2].ans1^tr[p*2+1].ans1;
tr[p].ans0=tr[p*2].ans0^tr[p*2+1].ans0;
tr[p].cnt1=tr[p*2].cnt1^tr[p*2+1].cnt1;
tr[p].cnt0=tr[p*2].cnt0^tr[p*2+1].cnt0;
}
void pushdown(int p){
if(tr[p].lazy1){ // 最远 和 次远 交换
tr[p].lazy1=0;
tr[p*2].lazy1^=1,tr[p*2+1].lazy1^=1;
swap(tr[p*2].ans0,tr[p*2].cnt0);
swap(tr[p*2].ans1,tr[p*2].cnt1);
swap(tr[p*2+1].ans0,tr[p*2+1].cnt0);
swap(tr[p*2+1].ans1,tr[p*2+1].cnt1);
}
if(tr[p].lazy2){ // 奇数偶数 交换
tr[p].lazy2=0;
tr[p*2].lazy2^=1,tr[p*2+1].lazy2^=1;
swap(tr[p*2].ans0,tr[p*2].ans1);
swap(tr[p*2].cnt0,tr[p*2].cnt1);
swap(tr[p*2+1].ans0,tr[p*2+1].ans1);
swap(tr[p*2+1].cnt0,tr[p*2+1].cnt1);
}
}
void build(int p,int l,int r){
tr[p].l=l,tr[p].r=r;
tr[p].lazy1=tr[p].lazy2=0;
if(l==r){
tr[p].ans0=0,tr[p].ans1=mxx[rk[l]];
tr[p].cnt0=0,tr[p].cnt1=mx[rk[l]];
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
pushup(p);
}
void change_1(int p,int l,int r){ // 最远 和 次远 交换
if(tr[p].l>=l && tr[p].r<=r){
tr[p].lazy1^=1;
swap(tr[p].ans0,tr[p].cnt0);
swap(tr[p].ans1,tr[p].cnt1);
return;
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)/2;
if(l<=mid) change_1(p*2,l,r);
if(r>mid) change_1(p*2+1,l,r);
pushup(p);
}
void change_2(int p,int l,int r){ // 奇数偶数 交换
if(tr[p].l>=l && tr[p].r<=r){
tr[p].lazy2^=1;
swap(tr[p].ans0,tr[p].ans1);
swap(tr[p].cnt0,tr[p].cnt1);
return;
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)/2;
if(l<=mid) change_2(p*2,l,r);
if(r>mid) change_2(p*2+1,l,r);
pushup(p);
}
}T;
void solve1(int x,int y){ // 最远 和 次远 交换
int fx=top[x],fy=top[y];
while(fx!=fy){
if(dep[fx]>dep[fy]){
T.change_1(1,dfn[fx],dfn[x]);
x=fa[fx],fx=top[x];
}
else{
T.change_1(1,dfn[fy],dfn[y]);
y=fa[fy],fy=top[y];
}
}
if(dfn[x]<dfn[y]) T.change_1(1,dfn[x],dfn[y]);
else T.change_1(1,dfn[y],dfn[x]);
}
void solve2(int x,int y){ // 奇数偶数 交换
int fx=top[x],fy=top[y];
while(fx!=fy){
if(dep[fx]>dep[fy]){
T.change_2(1,dfn[fx],dfn[x]);
x=fa[fx],fx=top[x];
}
else{
T.change_2(1,dfn[fy],dfn[y]);
y=fa[fy],fy=top[y];
}
}
if(dfn[x]<dfn[y]) T.change_2(1,dfn[x],dfn[y]);
else T.change_2(1,dfn[y],dfn[x]);
}
int ask(int x,int y){
int fx=top[x];
while(dep[fa[fx]]>dep[y]){
x=fa[fx],fx=top[x];
}
if(dep[fx]>dep[y]) x=fx;
while(fa[x]!=y) x=fa[x];
return x;
}
signed main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
int n,m;
scanf("%lld%lld",&n,&m);
for(int i=1;i<n;i++){
int x,y;
scanf("%lld%lld",&x,&y);
add(x,y),add(y,x);
}
dfs1(1,0);
dfs2(1,1);
dfs_1(1,0);
dfs_2(1,0);
T.build(1,1,n);
int rt=1;
int las;
if(ask_dist(rt,pot1)<ask_dist(rt,pot2)){
las=pot1;
solve1(rt,pot1);
}
else{
las=pot2;
solve1(rt,pot2);
}
for(int i=1;i<=m;i++){
int op,x;
scanf("%lld",&op);
solve1(rt,las);
if(op==1){
int u,v;
scanf("%lld%lld%lld",&u,&v,&x);
solve2(u,v);
}
else{
int u;
scanf("%lld%lld",&u,&x);
int lca=ask_lca(rt,u);
if(rt==u) T.change_2(1,1,n);
else if(lca==u){
int k=ask(rt,u);
T.change_2(1,1,n);
T.change_2(1,dfn[k],dfn[k]+siz[k]-1);
}
else{
T.change_2(1,dfn[u],dfn[u]+siz[u]-1);
}
rt=x;
}
if(ask_dist(x,pot1)<ask_dist(x,pot2)){
las=pot1;
solve1(x,pot1);
}
else{
las=pot2;
solve1(x,pot2);
}
printf("%lld\n",T.tr[1].ans1);
rt=x;
}
}
社会黄油飞#
对于限制
为了不存在啥都不选的情况,我们每回强制选一个,可以先把这条边的流退回去,然后再跑网络流。
code
// ubsan: undefined
// accoders
// socialbutterfly 社会黄油飞
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=6*1e3+10;
const int E=3*1e6+10;
const int inf=(1ll<<50);
struct edge{
int u,v;
}e[N];
int head[N*2],nex[E],ver[E],edge[E],tot=1;
void add(int x,int y,int w){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot,edge[tot]=w;
ver[++tot]=x,nex[tot]=head[y],head[y]=tot,edge[tot]=0;
}
int st,ed;
queue<int> q;
int dep[E],cur[E];
int bfs(){
memset(dep,0,sizeof(int)*(ed+1));
dep[st]=1;
q.push(st);
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(dep[y] || edge[i]<=0) continue;
dep[y]=dep[x]+1;
q.push(y);
}
}
if(dep[ed]) return 1;
else return 0;
}
int dfs(int x,int flow){
if(x==ed) return flow;
for(int i=cur[x];i;i=nex[i]){
cur[x]=i;
int y=ver[i];
if(dep[y]==dep[x]+1 && edge[i]>0){
int d=dfs(y,min(flow,edge[i]));
if(d>0){
edge[i]-=d;
edge[i^1]+=d;
return d;
}
}
}
return 0;
}
int ans=0;
int Dinic(){
while(bfs()){
for(int i=1;i<=ed;i++) cur[i]=head[i];
while(int d=dfs(st,inf)){
ans+=d;
}
}
return ans;
}
signed main(){
// freopen("in.in","r",stdin);
freopen("socialbutterfly.in","r",stdin);
freopen("socialbutterfly.out","w",stdout);
int n,m,lim;
scanf("%lld%lld%lld",&n,&m,&lim);
st=n+m+1,ed=st+1;
int sum=m;
for(int i=1;i<=m;i++){
scanf("%lld%lld",&e[i].u,&e[i].v);
add(st,i,1);
add(i,m+e[i].u,inf);
add(i,m+e[i].v,inf);
}
for(int i=1;i<=n;i++) add(m+i,ed,lim);
int getans=0;
for(int p=1;p<=n;p++){
int tmp;
for(int i=head[m+p];i;i=nex[i]){
int y=ver[i];
if(y==ed){
edge[i]=0;
edge[i^1]=0;
tmp=i;
break;
}
}
for(int i=head[m+p];i;i=nex[i]){
int y=ver[i];
if(y<=m){
int flow=edge[i];
edge[i]=0;
edge[i^1]=inf;
for(int j=head[y];j;j=nex[j]){
int k=ver[j];
if(k==st){
edge[j]-=flow;
edge[j^1]+=flow;
ans-=flow;
break;
}
}
}
}
if(sum-Dinic()>0){
getans=1;
break;
}
edge[tmp]=lim;
}
if(getans) printf("Yes\n");
else printf("No\n");
}
省选模拟20#
装备#
我们讲所有的
code
#include<bits/stdc++.h>
using namespace std;
const int N=2*1e5+5;
int head[N],nex[N*2],ver[N*2],tot=1;
bool flat[N*2],vis[N];
int a[N],b[N];
void add(int x,int y){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot;
flat[tot]=1;
ver[++tot]=x,nex[tot]=head[y],head[y]=tot;
}
int c[N],cnt[N],rt[N],col[N],num=0,able[N];
int dfn[N],siz[N],idx=0,dep[N],f[N];
int ans[N],anss[N];
int sum=0;
unordered_map<int,int> rk[N],chan[N];
void dfs3(int x,int fa){
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fa) continue;
if(flat[i]) chan[x][y]=1;
else chan[y][x]=1;
dfs3(y,x);
}
}
void dfs2(int x,int fa){
f[x]=fa;
dep[x]=dep[fa]+1;
dfn[x]=++idx;
siz[x]=1;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fa) continue;
dfs2(y,x);
siz[x]+=siz[y];
}
}
void dfs(int x,int fa){
col[x]=num;
vis[x]=1;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(flat[i]) cnt[x]++;
if(y==fa) continue;
if(vis[y]){
able[num]=1;
continue;
}
dfs(y,x);
}
if(!cnt[x]) rt[num]=x;
}
signed main(){
freopen("equipment.in","r",stdin);
freopen("equipment.out","w",stdout);
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
for(int i=1;i<=m;i++){
scanf("%d%d",&a[i],&b[i]);
add(a[i],b[i]);
rk[a[i]][b[i]]=i;
}
for(int i=1;i<=n;i++){
if(!vis[i]){
++num;
dfs(i,0);
if(!able[num])dfs2(rt[num],0);
}
}
for(int p=m;p>=1;p--){
int colr=col[a[p]];
if(able[colr]) continue;
if(chan[a[p]][b[p]] || chan[b[p]][a[p]]) continue;
if(c[a[p]]==c[b[p]]) continue;
if(c[a[p]]>c[b[p]]){
chan[a[p]][b[p]]=1;
dfs2(a[p],b[p]);
}
if(c[a[p]]<c[b[p]]){
if(dfn[b[p]]>=dfn[rt[colr]] && dfn[b[p]]<=dfn[rt[colr]]+siz[rt[colr]]-1 && k>=dep[a[p]]-dep[rt[colr]]){
int tmp=a[p];
int sum1=0;
while(1){
anss[++sum1]=rk[tmp][f[tmp]];
chan[f[tmp]][tmp]=1;
tmp=f[tmp];
if(tmp==rt[colr]) break;
}
for(int i=sum1;i>=1;i--) ans[++sum]=anss[i];
k-=(dep[a[p]]-dep[rt[colr]]);
rt[colr]=a[p];
}
}
}
printf("%d\n",sum);
for(int i=1;i<=sum;i++){
printf("%d\n",ans[i]);
}
}
比赛#
首先设
然后考虑优化,发现最后获胜的是
再优化,我们考虑先枚举
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=505;
const int mod=998244353;
int dp[N][N][N];
int f[N][N][2],g[N][N];
int a[N];
int inv[N][N];
int qpow(int x,int p){
int ans=1;
while(p){
if(p&1) ans=(ans*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return ans;
}
signed main(){
freopen("tournament.in","r",stdin);
freopen("tournament.out","w",stdout);
int n;
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
f[i][i][0]=f[i][i][1]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
inv[i][j]=qpow(a[i]+a[j],mod-2);
}
}
for(int len=2;len<=n;len++){
for(int l=1;l+len-1<=n;l++){
int r=l+len-1;
for(int k=l;k<r;k++) g[l][r]=(g[l][r]+f[l][k][0]*f[k+1][r][1]%mod)%mod;
for(int x=l;x<=r;x++){
if(x>l) f[l][r][0]=(f[l][r][0]+g[l][x]*inv[l][x]%mod*a[l]%mod*f[x][r][0]%mod)%mod;
if(x<r) f[l][r][1]=(f[l][r][1]+g[x][r]*inv[r][x]%mod*a[r]%mod*f[l][x][1]%mod)%mod;
}
int px=qpow(r-l,mod-2);
f[l][r][0]=f[l][r][0]*px%mod;
f[l][r][1]=f[l][r][1]*px%mod;
}
}
for(int i=1;i<=n;i++){
printf("%lld\n",f[1][i][1]*f[i][n][0]%mod);
}
}
作者:bloss
出处:https://www.cnblogs.com/jinjiaqioi/p/17975647
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效