今天 海星 但是 好像没有做到应该做到的事情 如 想出正解 如 对拍 如 仔细检查qwq.
今天得分 105 T1 100 T2 5分 T3 自闭 不会 爆零
关于本题 由于状态不存在环什么的 所以好做一点有 起点和终点 都是 一个状态 所以也好做一点。
起点 必须拿一张牌 也就是开始拿一张牌 然后发现终点是n+1张牌 所以 有终点 只需要枚举当前得到第i张牌的概率 及 算出来期望 就行啦。
如 到k张牌停止的概率是 p(x=k) = 1*(n-1)/n *(n-2)/n *(n-3)/n...*(n-(k-2))/n *(k-1)/n...
那么期望显然 就是 E(x=k)=p(x=k)*k; 求个累和即可。可以发现这个式子每次变化都是有规律的所以我们O(n)递推即可。
考虑dp 设f[i] 表示已经得到了i张牌此时还需要拿多少张牌才能停止的期望牌数。
那么 f[n]=1; 那对于一个普通的i来说 f[i]=i/n+(n-i)/n*(f[i+1]+1);
发现直接推到 f[0] 即可。这个我有代码。
//#include<bits/stdc++.h> #include<iostream> #include<queue> #include<iomanip> #include<cctype> #include<cstdio> #include<deque> #include<utility> #include<cmath> #include<ctime> #include<cstring> #include<string> #include<cstdlib> #include<vector> #include<algorithm> #include<stack> #include<map> #include<set> #include<bitset> #define INF 2147483646 #define ll long long #define db double #define pii pair<ll,ll> #define mk make_pair #define us unsigned #define min(x,y) ((x)>(y)?(y):(x)) #define max(x,y) ((x)>(y)?(x):(y)) #define mod 998244353ll using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const int MAXN=10000010; ll N=10000001,Q; ll f[MAXN],n;//f[i]表示已经摸出了i张牌还需要摸的牌数 ll jc,in[MAXN]; int inv[MAXN]; inline ll ksm(ll b,ll p) { ll ans=1; while(p) { if(p&1)ans=(ans*b)%mod; b=b*b%mod; p=p>>1; } return ans; } inline void prepare() { jc=1; for(int i=1;i<=N;++i)jc=jc*i%mod; inv[N]=ksm(jc,mod-2); for(int i=N-1;i>=0;--i)inv[i]=((ll)inv[i+1])*(i+1)%mod; jc=1; for(int i=1;i<=N;++i) { in[i]=(inv[i]*jc)%mod; jc=jc*i%mod; } } signed main() { //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); freopen("a.in","r",stdin); freopen("a.out","w",stdout); Q=read();prepare(); while(Q--) { n=read();f[n]=1; for(int i=n-1;i>=0;--i) { f[i]=((i*in[n])%mod+(((n-i)*in[n])%mod)*(f[i+1]+1))%mod; } printf("%lld ",f[0]); } return 0; }
唯一不足的是逆元是3n的复杂度 是可以O(n) 推逆元的 但是我忘了qwq,还是考试过后再复习一下比较好。
这里我扒一篇题解的证明过来 还是很容易看出来的。
//#include<bits/stdc++.h> #include<iostream> #include<queue> #include<iomanip> #include<cctype> #include<cstdio> #include<deque> #include<utility> #include<cmath> #include<ctime> #include<cstring> #include<string> #include<cstdlib> #include<vector> #include<algorithm> #include<stack> #include<map> #include<set> #include<bitset> #define ll long long #define INF 1000000000 #define max(x,y) ((x)>(y)?(x):(y)) #define min(x,y) ((x)>(y)?(y):(x)) #define us unsigned #define mod 1000000007 using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin)),fs==ft)?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const int MAXN=3000010; int n,p; ll in[MAXN]; int main() { freopen("1.in","r",stdin); n=read();p=read();in[1]=1; for(int i=2;i<=n;++i)in[i]=(p-p/i)*in[p%i]%p; for(int i=1;i<=n;++i)printf("%lld ",in[i]); return 0; }
这道题 就比较...我很震惊的是我竟然没有思考出来 好像没有把简单的模型抽出来的样子。 考虑询问都是1的点无非就是在自己的子树中寻找一个dis大于当前询问的东西然后取min。
这个操作当然可以主席树做。可是考虑 对于任意一个点的询问k呢 那就是 k+disx 然后再在x的子树种寻找qwq。
如何限定区间?可持久化主席树?很不行主席树 的前缀和不支持取min操作 换句话说取min操作没有区间可加性。考虑主席树合并。
很稳但是观察此题 很有可能被卡 复杂度在 nlogn~nlognlogn 之间 所以容易被卡死。
换个思路 可以把询问离线然后把我们这些节点也丢进去然后排序这样就少了主席树限定大小的问题了只需要维护区间性的问题和区间取min的问题了。
可以dfs序建树就可以解决这个问题了qwq。 以后脑子要灵光一点Y。复杂度nlogn.
//#include<bits/stdc++.h> #include<iostream> #include<queue> #include<iomanip> #include<cctype> #include<cstdio> #include<deque> #include<utility> #include<cmath> #include<ctime> #include<cstring> #include<string> #include<cstdlib> #include<vector> #include<algorithm> #include<stack> #include<map> #include<set> #include<bitset> #define ll long long #define INF 1000000000 #define max(x,y) ((x)>(y)?(x):(y)) #define min(x,y) ((x)>(y)?(y):(x)) #define us unsigned #define mod 1000000007 #define l(p) t[p].l #define r(p) t[p].r #define sum(p) t[p].sum #define zz p<<1 #define yy p<<1|1 using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,dp=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')dp=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*dp; } const int MAXN=2010,maxn=700010; int T,Q,n,len,id,top,cnt,rt; int dis[maxn],d[maxn],dfn[maxn],sz[maxn],ans[maxn]; int lin[maxn],nex[maxn<<1],ver[maxn<<1],e[maxn<<1]; struct jl { int op; int x,v; }s[maxn<<1]; struct wy { int l,r; int sum; }t[maxn<<2]; inline void add(int x,int y,int z) { ver[++len]=y; nex[len]=lin[x]; lin[x]=len; e[len]=z; } inline void dfs(int x,int father) { dfn[x]=++id;sz[x]=1; for(int i=lin[x];i;i=nex[i]) { int tn=ver[i]; if(tn==father)continue; d[tn]=d[x]+1; dis[tn]=dis[x]+e[i]; dfs(tn,x); sz[x]+=sz[tn]; } } inline int cmp(jl a,jl b){return a.v==b.v?a.op<b.op:a.v>b.v;} inline void build(int p,int l,int r) { l(p)=l;r(p)=r; if(l==r) { sum(p)=INF; return; } int mid=(l+r)>>1; build(zz,l,mid); build(yy,mid+1,r); sum(p)=min(sum(zz),sum(yy)); } inline void change(int p,int x,int k) { if(l(p)==r(p)) { sum(p)=k; return; } int mid=(l(p)+r(p))>>1; if(x<=mid)change(zz,x,k); else change(yy,x,k); sum(p)=min(sum(zz),sum(yy)); } inline int ask(int p,int l,int r) { if(l<=l(p)&&r>=r(p))return sum(p); int mid=(l(p)+r(p))>>1; int ansl=INF,ansr=INF; if(l<=mid)ansl=ask(zz,l,r); if(r>mid)ansr=ask(yy,l,r); return min(ansl,ansr); } int main() { freopen("b.in","r",stdin); freopen("b.out","w",stdout); T=read();n=read(); for(int i=2;i<=n;++i) { int x,y,z; x=read();y=read();z=read(); add(x,y,z);add(y,x,z); } dfs(1,0); Q=read(); for(int i=1;i<=Q;++i) { int x,k; x=read();k=read(); s[++top]=(jl){i,x,dis[x]+k}; } for(int i=1;i<=n;++i)s[++top]=(jl){0,i,dis[i]}; sort(s+1,s+1+top,cmp); build(1,1,id); for(int i=1;i<=top;++i) { //cout<<s[i].op<<' '<<s[i].v<<endl; if(s[i].op) { int w=ask(1,dfn[s[i].x],dfn[s[i].x]+sz[s[i].x]-1); if(w==INF)ans[s[i].op]=-1; else ans[s[i].op]=w-d[s[i].x]; } else change(1,dfn[s[i].x],d[s[i].x]); } for(int i=1;i<=Q;++i)printf("%d ",ans[i]); return 0; }
题解还给出了一个比较nb的方法 考虑对于大小问题排过序之后直接O(n)扫描 。但是这个扫描也具有区间的性质所以可以考虑CDQ分治了。
三维偏序问题 1 子树内外的关系 2 dis大小的问题 处理好这三个我认为就好了。
其中其中对于 1 可以dfs序判断或者采用O(1) LCA的方法判断 对于2 可以直接在外面排好序 然后内部直接归并。统计答案的时候直接指针暴力扫。
复杂度nlogn TAT
说好了要讲题解 讲到了CDQ分治qwq 题解中是这样解决区间的问题的 考虑线段树分治把每个问题分成logn个区间
而直接 暴力递归线段树 回溯时归并一下点 然后就完成了 复杂度 Qlogn+nlogn。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<vector> #include<algorithm> #include<cmath> #define P puts("lala") #define cp cerr<<"lala"<<endl #define ln putchar(' ') #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; inline int read() { char ch=getchar();int g=1,re=0; while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();} while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar(); return re*g; } typedef long long ll; typedef pair<int,int> pii; const int N=700009; int head[N],cnt=0; struct node { int to,next,w; }e[N<<1]; inline void add(int x,int y,int w) { e[++cnt]=(node){y,head[x],w}; head[x]=cnt; e[++cnt]=(node){x,head[y],w}; head[y]=cnt; } int n,q; const int inf=0x3f3f3f3f; struct ASK { int id,x,k,ans; }ask[N]; bool operator < (ASK a,ASK b) { return a.k<b.k; } int dep[N],dis[N],dfn[N],efn[N],tot=0,is[N]; void dfs(int u,int fa,int dp,int ds) { dep[u]=dp; dis[u]=ds; dfn[u]=++tot; is[tot]=u; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(v==fa) continue; dfs(v,u,dp+1,ds+e[i].w); } efn[u]=tot; } pii p[N]; // (ds,dp) vector<int>Q[N<<2]; void hang(int o,int l,int r,int x,int y,int i) { if(x<=l&&r<=y) {Q[o].pb(i); return ;} int mid=l+r>>1; if(x<=mid) hang(o<<1,l,mid,x,y,i); if(y>mid) hang(o<<1|1,mid+1,r,x,y,i); } pii tmp[N]; int sufmin[N]; void solve(int o,int l,int r) { if(l==r) { for(int i=0,sz=Q[o].size();i<sz;++i) { int u=Q[o][i]; if(p[l].fi>=ask[u].k) ask[u].ans=min(ask[u].ans,p[l].se); } return ; } int mid=l+r>>1; solve(o<<1,l,mid); solve(o<<1|1,mid+1,r); int i=l,j=mid+1,k=l; while(i<=mid&&j<=r) if(p[i]<p[j]) tmp[k]=p[i],i++,k++; else tmp[k]=p[j],j++,k++; while(i<=mid) tmp[k]=p[i],i++,k++; while(j<=r) tmp[k]=p[j],j++,k++; for(i=l;i<=r;++i) p[i]=tmp[i]; sufmin[r]=p[r].se; for(i=r-1;i>=l;--i) sufmin[i]=min(sufmin[i+1],p[i].se); int p1=l,p2=0,sz=Q[o].size(); for(;p2<sz;++p2) { int u=Q[o][p2]; while(p1<=r&&p[p1].fi<ask[u].k) p1++; if(p1<=r) ask[u].ans=min(ask[u].ans,sufmin[p1]); else break; } } int Ans[N]; void wj() { freopen("b.in","r",stdin); freopen("b.out","w",stdout); } int main() { wj(); int id=read(); n=read(); for(int i=1;i<n;++i) { int x=read(),y=read(),w=read(); add(x,y,w); } dfs(1,0,0,0); q=read(); for(int i=1;i<=q;++i) { ask[i].id=i; ask[i].x=read(); ask[i].k=read(); ask[i].ans=inf; ask[i].k+=dis[ask[i].x]; } sort(ask+1,ask+q+1); for(int i=1;i<=q;++i) hang(1,1,n,dfn[ask[i].x],efn[ask[i].x],i); for(int i=1;i<=n;++i) p[i]=pii(dis[is[i]],dep[is[i]]); solve(1,1,n); for(int i=1;i<=q;++i) { if(ask[i].ans==inf) Ans[ask[i].id]=-1; else Ans[ask[i].id]=ask[i].ans-dep[ask[i].x]; } for(int i=1;i<=q;++i) printf("%d ",Ans[i]); return 0; }
我啥都不会 啥都不懂qwq 咕了qwq。