(部分)多校补题集

hdu1 04 Ball(bitset)

把所有边升序排序后,枚举中间大小的边\(e\)

考虑对每个点\(i\)记录所有\(dis(i,j)\le e\)\(j\)构成的集合\(S_i\)

在枚举到边\((u,v,w)\)时,以该边为中位数的三角形答案为\(S_i \cap \bar{S_j}\)

利用bitset容易维护

#include<bits/stdc++.h>
#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 Fill(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int inf=2139062143;
const int MOD=998244353;
const int MAXN=2010;
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;
}
inline ll readll()
{
    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;
}
namespace CALC
{
    inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:a+b;}
    inline int mns(int a,int b){return a-b<0?a-b+MOD:a-b;}
    inline int mul(int a,int b){return (1LL*a*b)%MOD;}
    inline void inc(int &a,int b){a=pls(a,b);}
    inline void dec(int &a,int b){a=mns(a,b);}
    inline void tms(int &a,int b){a=mul(a,b);}
    inline int qp(int x,int t,int res=1)
        {for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;}
    inline int Inv(int x){return qp(x,MOD-2);}
}
using namespace CALC;
const int lim=200100;
int n,m,ntp[lim];
ll ans;
pii p[MAXN];
struct Edge{int w,x,y;};
bool operator < (const Edge &a,const Edge &b){return a.w<b.w;}
vector<Edge> v;
bitset<MAXN> cur[MAXN];
inline int dis(const pii &a,const pii &b)
{
    return abs(a.first-b.first)+abs(a.second-b.second);
}
void init(int n=2e5)
{
    ntp[1]=1;
    rep(i,2,n) rep(j,2,n/i) ntp[i*j]=1;
}
int main()
{
    init();
    rep(T,1,read())
    {
        n=read(),m=read(),ans=0;
        rep(i,1,n) p[i].first=read(),p[i].second=read();
        v.clear();
        rep(i,1,n) rep(j,i+1,n) v.push_back({dis(p[i],p[j]),i,j});
        sort(v.begin(),v.end());
        rep(i,1,n) cur[i].reset();
        for(auto t:v)
        {
            int i=t.x,j=t.y;
            if(!ntp[t.w])ans+=(cur[i]^cur[j]).count();
            cur[i][j]=1,cur[j][i]=1;
        }
        printf("%lld\n",ans);
    }
}

hdu1 07 Treasure(重构树+树状数组)

挺套路的但是板子有点多

先建克鲁斯卡尔重构树,这样查询即为子树查询

因为每个颜色的点数很少,对每个颜色建虚树后暴力向上更新,树状数组维护一下即可

(因为hdu特性这题需要略微卡一卡常数,下面的代码有一定概率在hdu上通过

一开始写了个树剖树状数组的\(\log^2\)复杂度的然后过不去,改成\(10\log\)还是过不去,然而事实上在本地这两个算法跑的差不多快。

#include<bits/stdc++.h>
#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 Fill(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int inf=2139062143;
const int MOD=998244353;
const int MAXN=200100;
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;
}
inline ll readll()
{
    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;
}
namespace CALC
{
    inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:a+b;}
    inline int mns(int a,int b){return a-b<0?a-b+MOD:a-b;}
    inline int mul(int a,int b){return (1LL*a*b)%MOD;}
    inline void inc(int &a,int b){a=pls(a,b);}
    inline void dec(int &a,int b){a=mns(a,b);}
    inline void tms(int &a,int b){a=mul(a,b);}
    inline int qp(int x,int t,int res=1)
        {for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;}
    inline int Inv(int x){return qp(x,MOD-2);}
}
using namespace CALC;
int n,m,q,col[MAXN],val[MAXN],fa[MAXN],tot,lim[MAXN];
int dep[MAXN],dfn,bl[MAXN],hvs[MAXN],sz[MAXN],in[MAXN];
int G[MAXN][2],f[MAXN][18];
vi vec[MAXN];
struct Edge{int u,v,w;}e[MAXN];
bool operator < (const Edge &x,const Edge &y){return x.w<y.w;}
bool cmp(int a,int b){return in[a]<in[b];}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void merge(int u,int v,int w)
{
    int fu=find(u),fv=find(v);
    if(fu!=fv) 
    {
        lim[++tot]=w,val[tot]=0;
        fa[fu]=fa[fv]=tot;
        G[tot][0]=fu;
        G[tot][1]=fv;
    }
}
namespace Fenwick
{
    ll c[MAXN];
    void mem(int lim){rep(i,1,lim) c[i]=0;}
    void mdf(int x,int w){for(;x<=tot;x+=x&-x) c[x]+=w;}
    ll getw(int x,ll res=0){for(;x;x-=x&-x) res+=c[x];return res;}
    ll query(int x){return getw(in[x]+sz[x]-1)-getw(in[x]-1);}
}
void kruskal()
{
    sort(e+1,e+m+1);
    rep(i,1,m) merge(e[i].u,e[i].v,e[i].w);
}
int getanc(int x,int w)
{
    dwn(i,17,0) if(lim[f[x][i]]<=w) x=f[x][i];
    return x;
}
void dfs(int x,int pa)
{
    fa[x]=pa,sz[x]=1,dep[x]=dep[pa]+1;
    f[x][0]=pa;
    for(int i=1;(1<<i)<dep[x];++i)
        f[x][i]=f[f[x][i-1]][i-1];
    if(!G[x][0]) return ;
    for(auto v:G[x])
        {dfs(v,x);sz[x]+=sz[v];if(sz[v]>sz[hvs[x]]) hvs[x]=v;}
}
void Dfs(int x,int anc)
{
    bl[x]=anc,in[x]=++dfn;
    if(!hvs[x]) return ;
    Dfs(hvs[x],anc);
    for(auto v:G[x]) if(v^hvs[x]) Dfs(v,v);
}
int lca(int x,int y)
{
    for(;bl[x]!=bl[y];x=fa[bl[x]])
        if(dep[bl[x]]<dep[bl[y]]) swap(x,y);
    return in[x]<in[y]?x:y;
}
unordered_map<int,int> lnk[MAXN];
unordered_map<int,ll> mx[MAXN];
int st[MAXN],tp;
ll sum[MAXN];
void addedge(int col,int u,int v)
{
    lnk[col][v]=u;
    if(!mx[col].count(v)) mx[col][v]=val[v];
    mx[col][u]=max(mx[col][u],mx[col][v]);
    sum[u]+=mx[col][v];
}
void ins(int col,int x)
{
    if(tp==1) {st[++tp]=x;return ;}
    int y=lca(x,st[tp]);
    if(st[tp]==y) return ;
    while(tp>1&&in[st[tp-1]]>=in[y]) addedge(col,st[tp-1],st[tp]),tp--;
    if(y!=st[tp]) addedge(col,y,st[tp]),st[tp]=y;
    st[++tp]=x;
}
void solve()
{
    n=tot=read(),m=read(),q=read();
    rep(i,1,n) col[i]=read(),vec[col[i]].push_back(i);
    rep(i,1,n) val[i]=read();
    rep(i,1,m) e[i].u=read(),e[i].v=read(),e[i].w=read();
    rep(i,1,n<<1) fa[i]=i,lim[i]=0,hvs[i]=0;
    lim[0]=inf;
    Fill(f,0);dfn=0;
    kruskal();
    dfs(tot,0);Dfs(tot,tot);
    Fenwick::mem(tot);
    rep(i,1,n) if(vec[i].size()) 
    {
        sort(vec[i].begin(),vec[i].end(),cmp);
        st[tp=1]=tot;
        for(auto x:vec[i]) ins(i,x);
        while(tp>1) addedge(i,st[tp-1],st[tp]),tp--;
        lnk[i][tot]=0;
        for(auto t:mx[i])
            Fenwick::mdf(in[t.first],t.second-sum[t.first]),sum[t.first]=0;
    }
    while(q--)
    {
        int op=read(),x=read();ll y=read();
        if(!op)
        {
            int c=col[x];
            Fenwick::mdf(in[x],y);
            y+=mx[c][x];
            for(int pa;pa=lnk[c][x];x=lnk[c][x])
            {
                Fenwick::mdf(in[pa],max(0LL,y-mx[c][pa])-y+mx[c][x]);
                mx[c][x]=y;
                if(y<=mx[c][pa]) break;
            }
            if(x==tot) mx[c][x]=y;
        }
        else 
            printf("%lld\n",Fenwick::query(getanc(x,y)));
    }
    rep(i,1,n) vec[i].clear(),lnk[i].clear(),mx[i].clear();
    rep(i,1,tot) G[i][0]=G[i][1]=0;
}
int main()
{
    rep(T,1,read()) solve();
}

hdu2 05 Slayers Come(线段树dp)

每个技能实际对应一个区间,对\(a_i-b_{i-1}\)\(L_i\)分别排序后利用并查集可以求出区间左端点,右端点同理。

问题转化为求若干区间将整个区间覆盖的方案数

将所有区间按右端点升序左端点降序排序,令\(f_i\)表示区间\([1,i]\)恰好被覆盖且\(i+1\)未被覆盖的方案数

则对一个新的区间\([l,r]\),影响为:

\[f_r+=\sum\limits_{i=l-1}^r f_i \]

\[f_i*=2,\ i\in[0,l-2] \]

使用线段树优化即可

#include<bits/stdc++.h>
#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 Fill(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int inf=2139062143;
const int MOD=998244353;
const int MAXN=200100;
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;
}
inline ll readll()
{
    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;
}
namespace CALC
{
    inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:a+b;}
    inline int mns(int a,int b){return a-b<0?a-b+MOD:a-b;}
    inline int mul(int a,int b){return (1LL*a*b)%MOD;}
    inline void inc(int &a,int b){a=pls(a,b);}
    inline void dec(int &a,int b){a=mns(a,b);}
    inline void tms(int &a,int b){a=mul(a,b);}
    inline int qp(int x,int t,int res=1)
        {for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;}
    inline int Inv(int x){return qp(x,MOD-2);}
}
using namespace CALC;
int n,m,a[MAXN],b[MAXN],fa[MAXN];
pii g[MAXN],seg[MAXN];
struct skill{int x,l,r,id;}sk[MAXN];
bool cmp1(const skill &a,const skill &b){return a.l<b.l;}
bool cmp2(const skill &a,const skill &b){return a.r<b.r;}
bool cmp(const pii &a,const pii &b)
{
    return a.second<b.second||(a.second==b.second&&a.first>b.first);
}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int sum[MAXN<<2],tag[MAXN<<2];
void build(int k,int l,int r)
{
    tag[k]=1;if(l==r) {sum[k]=!l;return ;}
    int mid=l+r>>1;
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    sum[k]=pls(sum[k<<1],sum[k<<1|1]);
}
void pshd(int k)
{
    tms(sum[k<<1],tag[k]),tms(sum[k<<1|1],tag[k]);
    tms(tag[k<<1],tag[k]),tms(tag[k<<1|1],tag[k]);
    tag[k]=1;
}
void mdf(int k,int l,int r,int a,int b)
{
    if(a<=l&&r<=b) {inc(sum[k],sum[k]),inc(tag[k],tag[k]);return ;}
    int mid=l+r>>1;if(tag[k]!=1) pshd(k);
    if(a<=mid) mdf(k<<1,l,mid,a,b);
    if(b>mid) mdf(k<<1|1,mid+1,r,a,b);
    sum[k]=pls(sum[k<<1],sum[k<<1|1]);
}
void upd(int k,int l,int r,int x,int w)
{
    inc(sum[k],w);if(l==r) return ;
    int mid=l+r>>1;if(tag[k]!=1) pshd(k);
    if(x<=mid) upd(k<<1,l,mid,x,w);
    else upd(k<<1|1,mid+1,r,x,w);
}
int query(int k,int l,int r,int a,int b)
{
    if(a<=l&&r<=b) return sum[k];
    int mid=l+r>>1,res=0;if(tag[k]!=1) pshd(k);
    if(a<=mid) res=query(k<<1,l,mid,a,b);
    if(b>mid) inc(res,query(k<<1|1,mid+1,r,a,b));
    return res;
}
void solve()
{
    n=read(),m=read();
    rep(i,1,n) a[i]=read(),b[i]=read(),fa[i]=i;
    rep(i,1,m) sk[i].x=read(),sk[i].l=read(),sk[i].r=read(),sk[i].id=i;
    sort(sk+1,sk+m+1,cmp1);
    rep(i,2,n) g[i]={a[i]-b[i-1],i};
    sort(g+2,g+n+1);
    int j=n;
    dwn(i,m,1)
    {
        while(j>=2&&g[j].first>=sk[i].l) fa[g[j].second]=find(g[j].second-1),j--;
        seg[sk[i].id].first=find(sk[i].x);
    }
    sort(sk+1,sk+m+1,cmp2);
    rep(i,1,n) fa[i]=i,g[i]={a[i]-b[i+1],i};
    sort(g+1,g+n);j=n-1;
    dwn(i,m,1)
    {
        while(j&&g[j].first>=sk[i].r) fa[g[j].second]=find(g[j].second+1),j--;
        seg[sk[i].id].second=find(sk[i].x);
    }
    sort(seg+1,seg+m+1,cmp);
    build(1,0,n);
    rep(i,1,m) 
    {
        int l=seg[i].first,r=seg[i].second;
        int w=query(1,0,n,l-1,r);
        upd(1,0,n,r,w);
        if(l>=2) mdf(1,0,n,0,l-2);
    }
    printf("%d\n",query(1,0,n,n,n));
}
int main()
{
    rep(T,1,read()) solve();
}

hdu2 08 Keyboard Warrior(哈希)

开一个栈存储每一段的字符以及长度,每一段的哈希值为等比数列求和容易计算

每次在插入新字符的时候check是否存在子串,将原串的末尾字符拿出来单独考虑,前面的部分利用哈希判断即可

有一些特殊情况如原串只有一种字符等,判掉即可

#include<bits/stdc++.h>
#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 Fill(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int inf=2139062143;
const int MOD=998244353;
const int MAXN=200100;
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;
}
inline ll readll()
{
    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;
}
namespace CALC
{
    inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:a+b;}
    inline int mns(int a,int b){return a-b<0?a-b+MOD:a-b;}
    inline int mul(int a,int b){return (1LL*a*b)%MOD;}
    inline void inc(int &a,int b){a=pls(a,b);}
    inline void dec(int &a,int b){a=mns(a,b);}
    inline void tms(int &a,int b){a=mul(a,b);}
    inline int qp(int x,ll t,int res=1)
        {for(t%=(MOD-1);t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;}
    inline int Inv(int x){return qp(x,MOD-2);}
}
using namespace CALC;
const int bas=233,inv=Inv(bas-1);
int n,m,ans=0,tot;
int hsh[MAXN];
ll sum[MAXN];
pair<int,ll> vec[MAXN];
char s[MAXN];
inline int hshval(int ch,ll len)
{
    return mul(ch,mul(mns(qp(bas,len),1),inv));
}
int getw(int l,int r)
{
    return mns(hsh[r],mul(hsh[l-1],qp(bas,sum[r]-sum[l-1])));
}
int solve()
{
    n=read(),m=read(),ans=0;
    scanf("%s",s+1);
    char ed=s[n];int lasnum=0;
    while(s[n]==ed) n--,lasnum++;
    int strval=0,pwlen=1;
    rep(i,1,n) strval=pls(mul(strval,bas),s[i]-'a'+1),tms(pwlen,bas);
    getchar();tot=0;
    rep(i,1,m) 
    {
        char ch=getchar();int len=read();
        if(!len||ans) continue;
        if(isalpha(ch))
        {
            if(ch==ed&&len>=lasnum)
            {
                if(!n) ans=1;
                else if(sum[tot]>=n)
                {
                    int p=upper_bound(sum,sum+tot+1,sum[tot]-n)-sum;
                    int w=getw(p,tot);
                    int len2=sum[tot]-n-sum[p-1];
                    dec(w,mul(hshval(vec[p].first,len2),pwlen));
                    if(w==strval) ans=1;
                }
            }
            if(vec[tot].first==ch-'a'+1)
            {
                sum[tot]+=len,vec[tot].second+=len;
                hsh[tot]=pls(mul(hsh[tot-1],qp(bas,vec[tot].second)),hshval(vec[tot].first,vec[tot].second));
            }
            else 
            {
                hsh[tot+1]=pls(mul(hsh[tot],qp(bas,len)),hshval(ch-'a'+1,len));
                tot++,sum[tot]=sum[tot-1]+len;
                vec[tot]=make_pair(ch-'a'+1,len);
            }
        }
        else 
        {
            while(tot&&len&&vec[tot].second<=len) len-=vec[tot].second,tot--;
            if(!tot||!len) continue;
            vec[tot].second-=len,sum[tot]-=len;
            hsh[tot]=pls(mul(hsh[tot-1],qp(bas,vec[tot].second)),hshval(vec[tot].first,vec[tot].second));
        }
    }
    return ans;
}
int main()
{
    rep(T,1,read()) puts(solve()?"yes":"no");
}

hdu3 01 Equipment Upgrade(分治ntt)

\(E_i\)表示从\(i\)级升到\(n\)级的期望花费,容易得到式子:

\[E_i=c_i+p_iE_{i+1}+\frac{1-p_i}{\sum_{k=1}^i w_k}\sum\limits_{j=1}^i w_jE_{i-j} \]

移项得到:

\[E_{i+1}=\frac{1}{p_i}\left(E_i-c_i-\frac{1-p_i}{\sum_{k=1}^i w_k}\sum\limits_{j=1}^i w_jE_{i-j}\right) \]

即为一个卷积形式的递推式,关键在于一直\(E_n=0\)\(E_0\)未知,可以设\(E_i=a_iE_0+b_i\)

\(a_i,b_i\)仍分别为分治\(NTT\)形式,其中\(a_0=1,b_0=0\)

#include<bits/stdc++.h>
#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 Fill(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int inf=2139062143;
const int MOD=998244353;
const int MAXN=200100;
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;
}
inline ll readll()
{
    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;
}
namespace CALC
{
    inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:a+b;}
    inline int mns(int a,int b){return a-b<0?a-b+MOD:a-b;}
    inline int mul(int a,int b){return (1LL*a*b)%MOD;}
    inline void inc(int &a,int b){a=pls(a,b);}
    inline void dec(int &a,int b){a=mns(a,b);}
    inline void tms(int &a,int b){a=mul(a,b);}
    inline int qp(int x,int t,int res=1)
        {for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;}
    inline int Inv(int x){return qp(x,MOD-2);}
}
using namespace CALC;
const int inv100=Inv(100);
int n,ans,c[MAXN],p[MAXN],invp[MAXN],w[MAXN],coef[MAXN],pw[30],ipw[30];
int f[MAXN<<2],g[MAXN<<2];
namespace Poly
{
    int rev[MAXN<<2];
    vi res;
    int mem(int n)
    {
        int lg=1,lim=1;
        for(;lim<n;lim<<=1,lg++);
        rep(i,0,lim-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-2));
        return lim;
    }
    void ntt(int *a,int n,int f)
    {
        rep(i,0,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
        for(int i=1,t=1;i<n;i<<=1,++t)
        {
            int wn= f>0?pw[t]:ipw[t];for(int j=0;j<n;j+=i<<1)
            {
                int w=1,x,y;for(int k=0;k<i;++k,w=mul(w,wn))
                    x=a[j+k],y=mul(a[j+k+i],w),a[j+k]=pls(x,y),a[j+k+i]=mns(x,y);
            }
        }
        if(f>0) return ;int nv=Inv(n);rep(i,0,n-1) a[i]=mul(a[i],nv);
    }
    void Mul(const int* a,int n,const int* b,int m)
    {
        static int A[MAXN<<2],B[MAXN<<2];
        int s=mem(n+m-1);
        if(min(n,m)<128)
        {
            res.assign(n+m-1,0);
            rep(i,0,n-1) rep(j,0,m-1) inc(res[i+j],mul(a[i],b[j]));
        }
        rep(i,0,n-1) A[i]=a[i];rep(i,n,s-1) A[i]=0;
        rep(i,0,m-1) B[i]=b[i];rep(i,m,s-1) B[i]=0;
        ntt(A,s,1);ntt(B,s,1);
        rep(i,0,s-1) tms(A[i],B[i]);
        ntt(A,s,-1);
        res.resize(n+m-1);rep(i,0,n+m-2) res[i]=A[i];
    }
    void div(int l,int r)
    {
        if(l==r) 
        {
            if(l==0) f[l]=1,g[l]=0;
            else 
            {
                f[l]=mns(f[l-1],mul(f[l],coef[l-1]));
                g[l]=mns(mns(g[l-1],c[l-1]),mul(g[l],coef[l-1]));
                tms(f[l],invp[l-1]),tms(g[l],invp[l-1]);
            }
            return ;
        }
        int mid=l+r>>1;div(l,mid);
        Mul(f+l,mid-l+1,w,r-l+1);
        rep(i,mid+1,r) inc(f[i],res[i-l-1]);
        Mul(g+l,mid-l+1,w,r-l+1);
        rep(i,mid+1,r) inc(g[i],res[i-l-1]);
        div(mid+1,r);
    }
}
void init()
{
    rep(i,1,25) pw[i]=qp(3,(MOD-1)/(1<<i)),ipw[i]=Inv(pw[i]);
}
void solve()
{
    n=read();
    rep(i,0,n-1) p[i]=mul(read(),inv100),invp[i]=Inv(p[i]),c[i]=read();
    int sum=0;
    rep(i,1,n-1) w[i]=read(),inc(sum,w[i]),coef[i]=mul(mns(1,p[i]),Inv(sum));
    rep(i,0,n) f[i]=g[i]=0;
    Poly::div(0,n);
    int a=f[n],b=g[n];
    printf("%d\n",mul(MOD-b,Inv(a)));
}
int main()
{
    init();
    rep(T,1,read()) solve();
}

hdu3 05 Spanning Tree Game(连通性dp)

将每条边拆成两条边,边权分别为\(a_i,\ b_i\),并对较大的边进行标记

将边按边权升 序,边权相同时被标记的边靠后,进行排序

考虑kruskal的过程,令\(f[i][state][j]\)表示前\(i\)条边,被选中的边连通状态为\(state\),已经选了\(j\)条来自\(a\)的边时最小生成森林的最大权值

考虑当前边\((u,v,w,tag)\)

  • 当该边未被标记时,该边可以任意选择。\(u,v\)不连通时,选择该边会使连通性改变且权值+=w;其余情况不变
  • 当该边被标记时,说明该边对应的另一条边已经被考虑过。若\(u,v\)未连通,则该边必选,使连通性改变且权值+=w;连通时,无论另一条边情况如何,该边都不会造成影响

顺次转移即可,为了方便统计已选择来自\(a\)的边数,对于\(a_i\ge b_i\)的情况可以默认先选择了\(b_i\),将\(f[0][state_0][num]\)置为\(0\)。其中\(state_0\)为零图,\(num\)\(a_i\ge b_i\)的边数

先搜索出所有连通性状态,转移复杂度为\(O(Bell(n)\ (n+m))\)

#include<bits/stdc++.h>
#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 Fill(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int inf=2139062143;
const int MOD=998244353;
const int MAXN=200100;
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;
}
inline ll readll()
{
    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;
}
namespace CALC
{
    inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:a+b;}
    inline int mns(int a,int b){return a-b<0?a-b+MOD:a-b;}
    inline int mul(int a,int b){return (1LL*a*b)%MOD;}
    inline void inc(int &a,int b){a=pls(a,b);}
    inline void dec(int &a,int b){a=mns(a,b);}
    inline void tms(int &a,int b){a=mul(a,b);}
    inline int qp(int x,int t,int res=1)
        {for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;}
    inline int Inv(int x){return qp(x,MOD-2);}
}
using namespace CALC;
int n,m,fa[20],tot,f[2][22010][35];
inline void chkmx(int &a,int b){a=max(a,b);}
struct Edge{int u,v,w,t;}e[300];
bool operator < (const Edge &a,const Edge &b)
{
    return a.w<b.w||(a.w==b.w&&a.t>b.t);
}
ull sts[22010];
unordered_map<ull,int> hsh;
void dfs(int x,int y)
{
    if(x>n)
    {
        sts[++tot]=0;
        rep(i,1,n) sts[tot]=sts[tot]<<4|fa[i];
        hsh[sts[tot]]=tot;
        return ;
    }
    rep(i,1,y+1) {fa[x]=i;dfs(x+1,max(i,y));}
}
void solve()
{
    n=read(),m=read();
    tot=0;hsh.clear();
    dfs(1,0);
    int num=0;
    rep(i,1,m)
    {
        int u=read(),v=read(),a=read(),b=read();
        if(a<b) e[i*2-1]=(Edge){u,v,a,1},e[i*2]=(Edge){u,v,b,0};
        else num++,e[i*2-1]=(Edge){u,v,b,2},e[i*2]=(Edge){u,v,a,0};
    }
    sort(e+1,e+m*2+1);
    rep(i,1,tot) rep(j,0,m) f[0][i][j]=-inf;
    f[0][tot][num]=0;
    rep(ne,1,m*2)
    {
        int now=ne&1,las=now^1;
        rep(i,1,tot) rep(j,0,m) f[now][i][j]=-inf;
        int u=e[ne].u,v=e[ne].v,w=e[ne].w,t=e[ne].t;
        rep(i,1,tot)
        {
            auto st=sts[i];
            int id=i,ww=w;
            dwn(j,n,1) fa[j]=st&15,st>>=4;
            if(fa[u]!=fa[v])
            {
                int x=min(fa[u],fa[v]),y=max(fa[u],fa[v]);
                rep(j,1,n)
                    if(fa[j]>y) fa[j]--;
                    else if(fa[j]==y) fa[j]=x;
                st=0;
                rep(j,1,n) st=st<<4|fa[j];
                id=hsh[st];
            }
            else ww=0;
            if(!t)rep(j,0,m) chkmx(f[now][id][j],f[las][i][j]+ww);
            else 
            {
                rep(j,0,m) chkmx(f[now][i][j],f[las][i][j]);
                if(t==1) rep(j,1,m) chkmx(f[now][id][j],f[las][i][j-1]+ww);
                else rep(j,0,m-1) chkmx(f[now][id][j],f[las][i][j+1]+ww);
            }
        }
    }
    rep(i,0,m) printf("%d\n",f[0][1][i]);
}
int main()
{
    rep(T,1,read()) solve();
}

hdu3 06 Dusk Moon(线段树+凸包+最小圆覆盖)

因为点是随机的,因此凸包上点的期望个数为\(\log\ n\)级别

用线段树分别维护上下凸壳,复杂度为\(O(n\log n)\)

每次查询的时候仍然分别维护上下凸壳,期望得到\(\log\ n\)级别的点数,对这些点做一次最小圆覆盖即可

#include<bits/stdc++.h>
#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 Fill(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int inf=2139062143;
const int MOD=998244353;
const int MAXN=100100;
const ld eps=1e-10;
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;
}
inline ll readll()
{
    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;
}
namespace CALC
{
    inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:a+b;}
    inline int mns(int a,int b){return a-b<0?a-b+MOD:a-b;}
    inline int mul(int a,int b){return (1LL*a*b)%MOD;}
    inline void inc(int &a,int b){a=pls(a,b);}
    inline void dec(int &a,int b){a=mns(a,b);}
    inline void tms(int &a,int b){a=mul(a,b);}
    inline int qp(int x,int t,int res=1)
        {for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;}
    inline int Inv(int x){return qp(x,MOD-2);}
}
using namespace CALC;
int n,q;
template<typename T>
struct Point
{
    T x,y;
    Point(T _x=0,T _y=0){x=_x,y=_y;}
    Point operator + (const Point &a) const {return Point(x+a.x,y+a.y);}
    Point operator - (const Point &a) const {return Point(x-a.x,y-a.y);}
    Point operator / (ld coef) const {return Point(x/coef,y/coef);}
    T len2()const {return x*x+y*y;}
    T operator * (const Point &a) const {return x*a.y-y*a.x;}
};
typedef Point<ll> pll;
typedef Point<ld> pld;
inline ld dis(const pld &a,const pld &b){return sqrtl((a-b).len2());}
pld getCenter(const pld &a,const pld &b,const pld &c)
{
    auto d=b-a,e=c-a;
    ld l1=d.len2()/2,l2=e.len2()/2,dd=d*e;
    return a+pld(l1*e.y-l2*d.y,d.x*l2-e.x*l1)/dd;
}
inline bool cmp0(const pll &a,const pll &b){return a.x<b.x||(a.x==b.x&&a.y>b.y);}
inline bool cmp1(const pll &a,const pll &b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
pll g[MAXN];
int tr[MAXN<<2][2][40],v0[80],v1[80];
void merge(int *a,int *b,int *c,bool tag)
{
    int i=1,j=1;
    auto cmp=tag?cmp1:cmp0;
    c[0]=0;
    while(i<=a[0]&&j<=b[0])
    {
        if((*cmp)(g[a[i]],g[b[j]])) c[++c[0]]=a[i++];
        else c[++c[0]]=b[j++];
    }
    while(i<=a[0]) c[++c[0]]=a[i++];
    while(j<=b[0]) c[++c[0]]=b[j++];
}
void getConvexHull(int *a,int *b,int *res,bool tag)
{
    static int tmp[80];
    merge(a,b,tmp,tag);
    res[0]=0;
    rep(i,1,tmp[0])
    {
        if(res[0]<2) {res[++res[0]]=tmp[i];continue;}
        while(res[0]>=2)
        {
            auto st=g[res[res[0]-1]],now=g[res[res[0]]];
            if(tag?(now-st)*(g[tmp[i]]-st)>=0LL:(now-st)*(g[tmp[i]]-st)<=0LL) res[0]--;
            else break;
        }
        res[++res[0]]=tmp[i];
    }
}
void mdf(int k,int l,int r,int p)
{
    if(l==r) return ;int mid=l+r>>1;
    if(p<=mid) mdf(k<<1,l,mid,p);
    else mdf(k<<1|1,mid+1,r,p);
    rep(i,0,1) getConvexHull(tr[k<<1][i],tr[k<<1|1][i],tr[k][i],i);
}
void build(int k,int l,int r)
{
    if(l==r) {rep(i,0,1) tr[k][i][0]=1,tr[k][i][1]=l;return ;}
    int mid=l+r>>1;
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    rep(i,0,1) getConvexHull(tr[k<<1][i],tr[k<<1|1][i],tr[k][i],i);
}
void query(int k,int l,int r,int a,int b)
{
    if(a<=l&&r<=b) 
    {
        getConvexHull(v0,tr[k][0],v0,0);
        getConvexHull(v1,tr[k][1],v1,1);
        return ;
    }
    int mid=l+r>>1;
    if(a<=mid) query(k<<1,l,mid,a,b);
    if(b>mid) query(k<<1|1,mid+1,r,a,b);
}
int tot;
pld res[MAXN];
int calc()
{
    tot=0;
    rep(i,1,v0[0]) res[++tot]=pld(g[v0[i]].x,g[v0[i]].y);
    rep(i,1,v1[0]) res[++tot]=pld(g[v1[i]].x,g[v1[i]].y);
    random_shuffle(res+1,res+tot+1);
    auto O=res[1];ld R=0;
    rep(i,2,tot) if(dis(res[i],O)>R+eps)
    {
        O=res[i],R=0;
        rep(j,1,i-1) if(dis(res[j],O)>R+eps)
        {
            O=(res[i]+res[j])/2,R=dis(O,res[i]);
            rep(k,1,j-1) if(dis(res[k],O)>R+eps)
                O=getCenter(res[k],res[j],res[i]),R=dis(O,res[i]);
        }
    }
    return ceil(R);
}
void solve()
{
    n=read(),q=read();
    rep(i,1,n) g[i].x=read(),g[i].y=read();
    build(1,1,n);
    rep(i,1,q) 
    {
        int t,x,y,k;
        scanf("%d",&t);
        if(t==1) {scanf("%d%d%d",&k,&x,&y);g[k]=pll(x,y);mdf(1,1,n,k);}
        else
        {
            scanf("%d%d",&x,&y);
            v0[0]=v1[0]=0;
            query(1,1,n,x,y);
            printf("%d\n",calc());
        }
    }
}
int main()
{
    rep(T,1,read()) solve();
}

hdu5 02 Jo loves counting(PN筛)

容易看出:

\[|Good_n|=\prod\limits_{i=1}^k \alpha_i,\ n=\prod\limits_{i=1}^k p_i^{\alpha_i} \]

\(f(n)=\frac{n}{\prod_{i=1}^k \alpha_i}\),则只需快速求\(f(i)\)的前缀和即可

显然\(f\)为积性函数,且\(f(p)=p,\ p\in \mathbb{P}\)

利用Powerful Number 筛求解:

\(g=id\),则\(G\)容易计算,考虑如何计算\(h(p^c)\),有:

\[h(p^c)=\frac{p^c}{c}-\sum\limits_{i=0}^{c-1} p^{c-i}h(p^i) \]

考虑\(h(p^{c-1})\),有:

\[\begin{aligned}\\ p\cdot h(p^{c-1})&=p\cdot\left(\frac{p^{c-1}}{c-1}-\sum\limits_{i=0}^{c-2} p^{c-i-1}h(p^i)\right)\\ 0&=\frac{p^c}{c-1}-\sum\limits_{i=0}^{c-1} p^{c-i}h(p^i) \end{aligned}\]

作差得到:\(h(p^c)=p^c(\frac{1}{c}-\frac{1}{c-1})\),套板子即可


Powerful Number 筛可以用来快速求积性函数\(f\)的前缀和,其中需要存在另一个前缀和容易计算的积性函数\(g\)满足\(f(p)=g(p),\ p\in \mathbb{P}\)

考虑\(f=g*h\),则\(h(1)=1,\ h(p)=0\),由此得到\(h\)仅在\(PN\)处取得有效值,而\(PN\)的个数是\(\sqrt{n}\)级别的

简单推一推式子可以得到:

\[F(n)=\sum\limits_{\substack{d=1\\d\ is\ PN}}h(d)G\left(\left\lfloor\frac{n}{d}\right\rfloor\right) \]

因此只需要搜索出所有\(PN\),分别求\(h\)的点值与\(g\)的前缀和即可

对于求\(h(p^c)\),往往可以通过\(h(p^c)=f(p^c)-\sum_{i=1}^c g(p^i)h(p^{c-i})\)这一式进行化简

#include<bits/stdc++.h>
#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 Fill(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int inf=2139062143;
const int MAXN=2001001;
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;
}
inline ll readll()
{
    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;
}
const ll MOD = 4179340454199820289LL;
inline ll add(ll x,ll y) {return x+y>=MOD?x+y-MOD:x+y;}
inline ll sub(ll x,ll y) {return x-y<0?x-y+MOD:x-y;}
inline ll mul(__int128 x,__int128 y){return (x*y)%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;
}
inline ll Inv(ll x){return qp(x,MOD-2);}
namespace PNS
{
    ll glbn,ans,h[MAXN][50];
    bool vish[MAXN][50],ntp[MAXN];
    int tot,prm[MAXN];
    void init(int n)
    {
        rep(i,2,n) 
        {
            if(!ntp[i]) prm[++tot]=i;
            rep(j,1,tot) if(prm[j]*i>n) break;
                else {ntp[i*prm[j]]=1;if(i%prm[j]==0) break;}
        }
        rep(i,1,tot) h[i][0]=1,h[i][1]=0,vish[i][0]=vish[i][1]=1;
    }
    inline ll G(__int128 n){return (n*(n+1)/2)%MOD;}
    void dfs(ll val,int id,ll res)
    {
        ans=add(ans,mul(res,G(glbn/val)));
        rep(i,id,tot)
        {
            if(i>1&&val>glbn/prm[i]/prm[i]) break;
            int c=2;
            for(ll x=val*prm[i]*prm[i];x<=glbn;x*=prm[i],++c)
            {
                if(!vish[i][c])
                {
                    h[i][c]=mul(qp(prm[i],c),sub(Inv(c),Inv(c-1)));
                    vish[i][c]=1;
                }
                if(h[i][c]) dfs(x,i+1,mul(res,h[i][c]));
            }
        }
    }
    ll solve(ll n)
    {
        glbn=n,ans=0;
        dfs(1,1,1);
        return mul(ans,Inv(n));
    }
}
int main()
{
    PNS::init(2000000);
    rep(T,1,read()) {ll n=readll();printf("%lld\n",PNS::solve(n));}
}

hdu8 07 Darnassus(根号乱搞+最小生成树)

发现一定存在一个最大边权小于等于\(n-1\)的生成树,因此只需要对所有边权小于等于\(n-1\)的边做最小生成树

用根号的复杂度分别枚举\(idx\)\(p_idx\)的差即可得到所有满足要求的边

再利用桶排序做\(kruskal\)即可

(有些卡常

#include<bits/stdc++.h>
#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 Fill(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int inf=2139062143;
const int MOD=998244353;
const int MAXN=50100;
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;
}
inline ll readll()
{
    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;
}
namespace CALC
{
    inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:a+b;}
    inline int mns(int a,int b){return a-b<0?a-b+MOD:a-b;}
    inline int mul(int a,int b){return (1LL*a*b)%MOD;}
    inline void inc(int &a,int b){a=pls(a,b);}
    inline void dec(int &a,int b){a=mns(a,b);}
    inline void tms(int &a,int b){a=mul(a,b);}
    inline int qp(int x,int t,int res=1)
        {for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;}
    inline int Inv(int x){return qp(x,MOD-2);}
}
using namespace CALC;
int n,m,p[MAXN],q[MAXN],vis[MAXN],fa[MAXN],ans;
int fst[MAXN],nxt[MAXN*450],cnt,p1[MAXN*450],p2[MAXN*450];
void add(int w,int u,int v)
{
    nxt[++cnt]=fst[w],fst[w]=cnt,p1[cnt]=u,p2[cnt]=v;
}
inline int calc(int i,int j){return abs(i-j)*abs(p[i]-p[j]);}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void solve()
{
    scanf("%d",&n);m=ans=cnt=0;
    rep(i,1,n) {scanf("%d",&p[i]);q[p[i]]=i;fa[i]=i;}
    rep(i,1,n-1) fst[i]=0;
    int lim=sqrt(n-0.5);
    rep(i,1,n)
    {
        rep(j,i+1,min(i+lim,n))
            if(calc(i,j)<n) add(calc(i,j),i,j);
        rep(j,p[i]+1,min(p[i]+lim,n))
            if(calc(i,q[j])<n)
                add(calc(i,q[j]),i,q[j]);
    }
    rep(i,1,n-1)
    {
        for(int j=fst[i];j;j=nxt[j])
        {
            int x=find(p1[j]),y=find(p2[j]);
            if(x!=y)
            {
                fa[x]=y,ans+=i;
                if((++m)==n-1) {printf("%d\n",ans);return ;}
            }
        }
    }
}
int main()
{
    rep(T,1,read()) solve();
}
posted @ 2022-08-30 21:38  jack_yyc  阅读(24)  评论(0编辑  收藏  举报