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:

\[f(n,k) = \frac{n-k+1}n + \frac 1n\sum_{j=1}^{k-1}(f(n-i,k-i)+1), f(n,1)=1 \]

然后随便找规律或者归纳一下就能得到

\[f(n,k)=1+\sum_{i=n-k+2}^n\frac 1i \]

最后答案是

\[\frac 1n\sum_{k=1}^nf(n,k)=2-\frac 1n\sum_{i=1}^n\frac 1i \]

当然经验丰富的选手可能看到 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

答案是

\[[y^k]\prod_{i=1}^n (1+x^{a_i}y) \]

考虑对每一项进行 FWT,最终 FWT 数组的每一位都形如

\[[y^k](1+y)^{x_{1,i}}(1-y)^{x_{-1,i}} \]

注意 \(x_{1,i}+x_{-1,i}=n\)。对确定的 \(k\) 和所有的 \(x_{-1,i}\),上面这个式子的第 \(k\) 项可以 NTT 计算。

最后再 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]<<' ';
}
posted @ 2024-11-12 15:52  EssnSlaryt  阅读(1)  评论(0编辑  收藏  举报