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;
}