2024.11.10 2024广西省赛
Solved:10/13
Upsolved:11/13
Penalty:920
Rank:1/169(N+1)
Dirt:53%
Problem | A | B | C | D | E | F | G | H | I | J | K | L | M | 题数 | 罚时 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Time | 123 | 3 | 47 | 11 | 18 | 105 | 26 | 155 | 5 | 197 | 10 | 920 | |||
dirt | 9 | 1 | 1 |
B,L,E,F,J:签到题
D
一看题就有种卡精度的直觉。直接写分数类,一发就过了。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; //typedef pair<ll,ll> pll; const int N=1e5+5; int n,x,l,r,v; struct frac{ ll a,b; frac(ll a,ll b):a(a),b(b){ll d=__gcd(a,b);a/=d,b/=d;} bool operator<(const frac& p)const{ return a*p.b<b*p.a; } }; map<frac,vector<pii>> mp; multiset<int> s; int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n>>x; for(int i=1;i<=n;++i){ cin>>l>>r>>v; if(l<=x)mp[frac(x-l,v)].push_back(pii(r-l,-1)); if(r<x)mp[frac(x-r,v)].push_back(pii(r-l,1)); else if(l<=x)mp[frac(0,1)].push_back(pii(r-l,1)); } int ans=0; for(auto [t,e]:mp){ for(auto [x,y]:e)if(y==1)s.insert(x); if(!s.empty())ans=max(ans,*s.begin()); for(auto [x,y]:e)if(y==-1)s.erase(s.find(x)); if(!s.empty())ans=max(ans,*s.begin()); } cout<<ans<<'\n'; }
H
开始写了 umap 套 map,然后 T 了。后来卡了很多发(包括但不限于:双哈希用一个ll存、改手写哈希、map改vector)还是 T。
最后改成 pair sort 过了。
百万级的 umap 和手写哈希都是非常慢的!!!理论O(1)的复杂度实际上根本跑不过 sort/lower_bound 的 log。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; typedef pair<ll,ll> pll; mt19937 rnd(time(0)); const int N=3005,M=4550005,base=2e9+5,p1=2e9+11,p2=2.1e9+11; int n,p,m,tot=0; ll a[N]; pll h[M]; int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n>>p>>m; for(int i=1;i<=n;++i)cin>>a[i]; for(int i=1;i<=n;++i){ ll hs=0,h1=0,h2=0; for(int j=i;j;--j){ hs=(hs*p+a[j])%m; h1=(h1*base+a[j]+1)%p1; h2=(h2*base+a[j]+1)%p2; h[++tot]=pll(hs,h1<<31|h2); } } sort(h+1,h+tot+1); ll ans=0; int i=1; while(i<=tot){ int j=i,k=i; ll sum=0; while(j<=tot&&h[j].first==h[i].first){ while(k<=tot&&h[k].second==h[j].second)++k; sum+=1ll*(k-j)*(k-j); j=k; } ans+=1ll*(j-i)*(j-i)-sum; i=j; } cout<<ans<<'\n'; }
A
推式子题。朴素dp:
然后随便找规律或者归纳一下就能得到
最后答案是
当然经验丰富的选手可能看到 input 3 output 11/6 就能猜到调和级数(问号)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e7+5,mod=998244353; int n; ll inv[N]; int main(){ cin>>n; inv[1]=1; for(int i=2;i<=n;++i)inv[i]=inv[mod%i]*(mod-mod/i)%mod; ll ans=0; for(int i=1;i<=n;++i)ans=(ans+inv[i])%mod; ans=((2-ans*inv[n])%mod+mod)%mod; cout<<ans<<'\n'; }
K
动态开点线段树+线段树上二分,写过几百遍的套路了。因为空间没开够爆了一发。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+5,V=N*120,M=1e9; int n,m,l,r,w; ll h; int rt,lc[V],rc[V],cnt; ll sum[V],tag[V]; void add(int x,int l,int r,int v){ sum[x]+=1ll*(r-l+1)*v; tag[x]+=v; } void pd(int x,int l,int r){ if(!lc[x])lc[x]=++cnt; if(!rc[x])rc[x]=++cnt; int mid=(l+r)>>1; add(lc[x],l,mid,tag[x]),add(rc[x],mid+1,r,tag[x]); tag[x]=0; } void upd(int& x,int l,int r,int L,int R,int v){ if(!x)x=++cnt; if(l==L&&r==R){ add(x,l,r,v); return; } pd(x,l,r); int mid=(l+r)>>1; if(R<=mid)upd(lc[x],l,mid,L,R,v); else if(L>mid)upd(rc[x],mid+1,r,L,R,v); else upd(lc[x],l,mid,L,mid,v),upd(rc[x],mid+1,r,mid+1,R,v); sum[x]=sum[lc[x]]+sum[rc[x]]; } ll qsum(int x,int l,int r,int L,int R){ if(!x)return 0; if(l==L&&r==R)return sum[x]; pd(x,l,r); int mid=(l+r)>>1; if(R<=mid)return qsum(lc[x],l,mid,L,R); if(L>mid)return qsum(rc[x],mid+1,r,L,R); return qsum(lc[x],l,mid,L,mid)+qsum(rc[x],mid+1,r,mid+1,R); } int qry(int x,int l,int r,int pos,ll v){ if(l==r)return l; pd(x,l,r); int mid=(l+r)>>1; if(pos<=mid){ ll s=qsum(lc[x],l,mid,pos,mid); if(v<=s)return qry(lc[x],l,mid,pos,v); else return qry(rc[x],mid+1,r,mid+1,v-s); } return qry(rc[x],mid+1,r,pos,v); } int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n>>m; for(int i=1;i<=n;++i){ cin>>l>>r>>w; upd(rt,1,M,l,r,w); } for(int i=1;i<=m;++i){ cin>>l>>h; if(qsum(rt,1,M,l+1,M)<h)cout<<"-1\n"; else cout<<qry(rt,1,M,l+1,h)-l<<'\n'; } }
M
贪心,能在子树里匹配的都匹配完。每个子树维护一个set存没匹配的节点的深度。启发式合并。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+5; int n,x,y; vector<int> e[N]; void adde(int x,int y){ e[x].push_back(y); } set<int> s[N]; int f[N],sz[N]; int find(int x){return x==f[x]?x:f[x]=find(f[x]);} ll ans=0; void mrg(int x,int y,int dep){ x=find(x),y=find(y); if(sz[x]<sz[y])swap(x,y); f[y]=x,sz[x]+=sz[y]; for(int d:s[y]){ if(s[x].find(d)!=s[x].end())ans+=2*(d-dep),s[x].erase(d); else s[x].insert(d); } } void dfs(int u,int f,int dep){ sz[u]=1,s[u].insert(dep); for(int v:e[u])if(v^f){ dfs(v,u,dep+1); mrg(u,v,dep); } } int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n; for(int i=1;i<n;++i){ cin>>x>>y; adde(x,y),adde(y,x); } for(int i=1;i<=n;++i)f[i]=i; dfs(1,0,0); cout<<ans<<'\n'; }
G
答案是
考虑对每一项进行 FWT,最终 FWT 数组的每一位都形如
注意
最后再 IFWT 回去即可。
简单来说就是先 FWT 再 IFWT,但是 FWT 的式子形式特殊可以直接写出形式化表达。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1<<17,M=1<<16,mod=998244353,inv2=(mod+1)/2; inline int inc(int x,int y){return x+y>=mod?x+y-mod:x+y;} inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;} inline int mul(int x,int y){return (ll)x*y%mod;} inline int qpow(int x,int y){ int res=1; for(;y;y>>=1)res=y&1?mul(res,x):res,x=mul(x,x); return res; } inline int inv(int x){return qpow(x,mod-2);} int re[N],w[2][N]; inline int getre(int n){ int len=1,bit=0; while(len<n)len<<=1,++bit; for(int i=1;i<len;++i)re[i]=(re[i>>1]>>1)|((i&1)<<(bit-1)); w[0][0]=w[1][0]=1,w[0][1]=qpow(3,(mod-1)/len),w[1][1]=inv(w[0][1]); for(int o=0;o<2;++o)for(int i=2;i<len;++i) w[o][i]=mul(w[o][i-1],w[o][1]); return len; } inline void NTT(int* a,int n,int o=0){ for(int i=1;i<n;++i)if(i<re[i])swap(a[i],a[re[i]]); int R; for(int k=1;k<n;k<<=1) for(int i=0,t=k<<1,st=n/t;i<n;i+=t) for(int j=0,nw=0;j<k;++j,nw+=st) R=mul(a[i+j+k],w[o][nw]),a[i+j+k]=dec(a[i+j],R),a[i+j]=inc(a[i+j],R); if(o){ R=inv(n); for(int i=0;i<n;++i)a[i]=mul(a[i],R); } } int t0[N],t1[N],t2[N]; inline void multi(const int* a,const int* b,int* c,int n,int m){ int len=getre(n+m+1); memset(t0,0,sizeof(int)*len),memcpy(t0,a,sizeof(int)*(n+1)); memset(t1,0,sizeof(int)*len),memcpy(t1,b,sizeof(int)*(m+1)); NTT(t0,len),NTT(t1,len); for(int i=0;i<len;++i)t0[i]=mul(t0[i],t1[i]); NTT(t0,len,1); memcpy(c,t0,sizeof(int)*(n+m+1)); } int n,k,m,len,a[N]; void FWT_xor(int* a,int m){ for(int k=1;k<len;k<<=1){ for(int i=0;i<len;i+=k<<1){ for(int j=0;j<k;++j){ int t=a[i+j+k]; a[i+j+k]=dec(a[i+j],t); a[i+j]=inc(t,a[i+j]); } } if(!~m) for(int i=0;i<len;++i) a[i]=mul(a[i],inv2); } } ll fac[N],inf[N]; int f[N],g[N]; void init(int n,int k){ fac[0]=1; for(int i=1;i<=n;++i)fac[i]=fac[i-1]*i%mod; inf[1]=1; for(int i=2;i<=n;++i)inf[i]=inf[mod%i]*(mod-mod/i)%mod; inf[0]=1; for(int i=1;i<=n;++i)inf[i]=inf[i-1]*inf[i]%mod; for(int i=0,_=1;i<=n;++i){ if(i<=k)f[i]=inf[i]*inf[k-i]%mod*_%mod; else f[i]=0; if(i<=n-k)g[i]=inf[i]*inf[n-k-i]%mod; else g[i]=0; _=mod-_; } multi(f,g,f,k,n-k); } ll C(int n,int m){ if(m<0||n<m)return 0; return fac[n]*inf[m]%mod*inf[n-m]%mod; } int c[M]; int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n>>k>>m; init(n,k); for(int i=1;i<=n;++i)cin>>a[i],++c[a[i]]; len=1; while(len<m)len<<=1; FWT_xor(c,1); for(int i=0;i<len;++i){ int t=1ll*(n-c[i]+mod)*inv2%mod; c[i]=f[t]; } FWT_xor(c,-1); for(int i=0;i<m;++i)cout<<c[i]<<' '; }
我愿意追随你的轨迹,不远万里,不问归期
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!