Comet OJ - Contest #2
A
code:
#include <cstdio> #include <algorithm> #define N 1000000 #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; ll f[N],g[N]; int main() { // setIO("input"); int i,j; f[1]=1,f[2]=1,g[2]=2; ll x; scanf("%lld",&x); if(x<=2) { printf("%lld\n",x+1); return 0; } for(i=3;;++i) { f[i]=g[i-1]/2; g[i]=g[i-1]+f[i]; if(g[i]>x) { printf("%d\n",i); return 0; } } return 0; }
B
推式子发现是二次函数的形式,套用二次函数公式好了.
code:
#include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; int main() { // setIO("input"); int i,j; double l,r,L,R; scanf("%lf%lf%lf%lf",&l,&r,&L,&R); double q=(L+R)*0.5; double sl=(l+q)*0.5; sl=max(l,min(sl,r)); printf("%.4f\n",max(0.0000,(double)(sl-l)/(r-l)*(q-sl))); return 0; }
C
感觉这个比 B 简单啊,直接枚举就好了.
code:
#include <cstdio> #include <map> #include <vector> #include <set> #include <cstring> #include <algorithm> #define ll long long #define mod 998244353 #define N 100006 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int fac[N],inv[N]; int qpow(int x,ll y) { int tmp=1; for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) tmp=(ll)tmp*x%mod; return tmp; } int INV(int x) { return qpow(x,mod-2); } void init() { fac[0]=inv[0]=1; int i,j; for(i=1;i<N;++i) fac[i]=(ll)fac[i-1]*i%mod,inv[i]=INV(fac[i]); } int C(int x,int y) { if(x<0||y<0||x<y) return 0; return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod; } int main() { // setIO("input"); init(); int n,x,y,ans=0,i,j,det; scanf("%d%d%d",&n,&x,&y); det=(ll)x*INV(y)%mod; for(i=1;i<=n;++i) { int tp=(ll)C(n,i)*qpow(det,1ll*i*(i-1)/2)%mod; (ans+=(ll)C(n,i)*qpow(det,(ll)i*(i-1)/2)%mod)%=mod; } printf("%d\n",(ans+1)%mod); return 0; }
D
枚举中心点,容斥原理算一算
code:
#include <bits/stdc++.h> #define N 4010 #define ll long long #define mod 998244353 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int edges,now,n; int hd[N<<1],to[N<<2],nex[N<<2],cnt[N<<1][N],sum[N],bin[N],ans[N]; void add(int u,int v) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; } void dfs(int u,int ff,int d) { if(u<=n) ++sum[d], ++cnt[now][d]; for(int i=hd[u];i;i=nex[i]) if(to[i]!=ff) dfs(to[i], u, d+1); } int main() { // setIO("input"); int i,j; scanf("%d",&n); bin[0]=1; for(i=1;i<=n;++i) bin[i]=bin[i-1]*2%mod; for(i=1;i<n;++i) { int u,v; scanf("%d%d",&u,&v); add(u,i+n),add(i+n,u); add(i+n,v),add(v,i+n); } for(i=1;i<=2*n;++i) { now=0; for(j=hd[i];j;j=nex[j]) ++now, dfs(to[j],i,1); int re=(i<=n); for(j=1;j<n;++j) { int mdl=bin[sum[j]]-1; for(int k=1;k<=now;++k) { (mdl+=mod-bin[cnt[k][j]]+1)%=mod; } (ans[j]+=(ll)mdl*bin[re]%mod)%=mod; re+=sum[j]; } memset(sum,0,sizeof sum); for(j=1;j<=now;++j) memset(cnt[j], 0, sizeof cnt[j]); } for(i=1;i<n;++i) printf("%d\n",(ans[i]+mod)%mod); return 0; }
E
我们发现图形是一个基环数森林.
如果是树形结构的话十分方便.
而我们可以将问题简化为如何处理环.
显然,我们要枚举起点,并将起点出发的边断开,然后维护一圈 $ans_{i}=A_{i}+B_{i} \times ans_{i-1}$.
这个满足结合律,用线段树维护即可.
code:
#include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <map> #include <queue> #define ll long long #define N 200008 #define mod 998244353 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int A[N],B[N],ans[N]; int qpow(int x,int y) { int tmp=1; for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) tmp=(ll)tmp*x%mod; return tmp; } int INV(int x) { return qpow(x,mod-2); } namespace seg { #define lson now<<1 #define rson now<<1|1 struct node { int a,b; node() { a=b=0; } node operator+(const node &t) const { node c; c.a=(ll)(t.a+(ll)t.b*a%mod)%mod; c.b=(ll)t.b*b%mod; return c; } }s[N<<2]; void build(int l,int r,int now) { if(l==r) { s[now].a=A[l]; s[now].b=B[l]; return; } int mid=(l+r)>>1; build(l,mid,lson),build(mid+1,r,rson); s[now]=s[lson]+s[rson]; } node query(int l,int r,int now,int L,int R) { if(l>=L&&r<=R) return s[now]; int mid=(l+r)>>1; if(L<=mid&&R>mid) return query(l,mid,lson,L,R)+query(mid+1,r,rson,L,R); else if(L<=mid) return query(l,mid,lson,L,R); else return query(mid+1,r,rson,L,R); } #undef lson #undef rson }; int n; int deg[N],p[N],go[N],seq[N],id[N],s[N]; queue<int>q; void solve_tree() { int i,j; for(i=1;i<=n;++i) if(!deg[i]) q.push(i); while(!q.empty()) { int u=q.front();q.pop(); int v=go[u]; --deg[v]; p[v]=(ll)(p[v]+(ll)(1-p[v]+mod)*s[u]%mod*p[u]%mod)%mod; if(deg[v]==0) q.push(v); } } void solve_circle(int x) { int i,j; int t=go[x],top=0; seq[++top]=x; while(t!=x) seq[++top]=t,t=go[t]; for(i=1;i<=top;++i) seq[top+i]=seq[i]; for(i=1;i<=top;++i) id[seq[i]]=i,deg[seq[i]]=0; for(i=2;i<=(top<<1);++i) { A[i]=p[seq[i]]; B[i]=(ll)(1-p[seq[i]]+mod)*s[seq[i-1]]%mod; } A[1]=A[top+1],B[1]=B[top+1]; seg::build(1,top<<1,1); for(i=1;i<=top;++i) { int u=seq[i]; seg::node an=seg::query(1,top<<1,1,i+2,i+top); ans[u]=(ll)((ll)an.b*p[seq[i+1]]%mod+an.a)%mod; } } int main() { // setIO("input"); int i,j; scanf("%d",&n); for(i=1;i<=n;++i) { int x,y; scanf("%d%d",&x,&y); p[i]=(ll)x*INV(y)%mod; } for(i=1;i<=n;++i) scanf("%d",&go[i]),++deg[go[i]]; for(i=1;i<=n;++i) { int x,y; scanf("%d%d",&x,&y); s[i]=(ll)x*INV(y)%mod; } solve_tree(); for(i=1;i<=n;++i) if(!deg[i]) ans[i]=p[i]; for(i=1;i<=n;++i) { if(deg[i]) solve_circle(i); printf("%d ",ans[i]); } return 0; }