(部分)多校补题集
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]\),影响为:
使用线段树优化即可
#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_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筛)
容易看出:
令\(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-1})\),有:
作差得到:\(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}\)级别的
简单推一推式子可以得到:
因此只需要搜索出所有\(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();
}