模拟52 考试总结

永远不要相信他的数据强度

考试经过

开题,T1感觉很sb半小时切了,拍上不管了,T2题目感觉很毒瘤,于是先打了T3和T4的暴力,然后推波柿子搞上T3的15部分分,剩不到一个小时回头看T2,看着样例解释脑补了一个贪心策略,然后一个\(n\log n\)的模拟,怕挂掉就写了\(20pts\)的测试点分治
实测100+100+35+0=235,由于后面新造了好多数据所以排名一直在变,前两个切了,然而T4暴力挂了,rank就炸了

T1.异或

据说可以直接算,不过我还是写了数位dp

#include <bits/stdc++.h>
using namespace std;
#define int long long
int bit[62],g[62];
inline int get(int l)
{
	int ans=0;
	for(int i=0;i<l;i++)ans+=(i+1)*bit[l-1-i];
	ans+=l+1;
	return ans;
}
int dfs(int lim,int x,int s)
{
	if(!x)return s+1;
	int ans=0;
	if((lim>>(x-1))&1)
	{
		ans+=g[x-1];
		ans+=dfs(lim,x-1,s+1);
	}
	else ans+=dfs(lim,x-1,0);
	return ans;
}
signed main()
{
	bit[0]=1;for(int i=1;i<=60;i++)bit[i]=bit[i-1]*2;
	g[0]=1;for(int i=1;i<=60;i++)g[i]=get(i);
	int n;cin>>n;
	cout<<dfs(n-1,60,0)<<endl;
	return 0;
}

T2.赌神

正确策略是:你每次按照剩的球等比例下注,把钱全下完,对手一定选当前数量最多的球落下,也就是让球数尽量平均,模拟即可
似乎不太好理性证明,但是可以感性理解
如果你的最优策略一旦确定,那么对面的操作对你的收益是没有影响的,这个策略会让你的收益更大
题解先用了dp,然后验证之后发现就是一个从 \(n\)维平面某个点走到原点的方案,显然可重集排列,所以直接一个柿子推出来

\[\frac{(\sum_{i=1}^n x_i)!}{\prod_{i=1}^nx_i!} \]

我用堆实现带一个\(log\),用桶模拟是\(O(n)\)

#include <bits/stdc++.h>
using namespace std;
const int mod=998244353;
const int N=1000050;
inline int read()
{
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x;
}
int a[N],inv[N],n;
priority_queue <pair<int,int> > q;
signed main()
{
	n=read();int sum=0;
	for(int i=1;i<=n;i++)
	{
		a[i]=read();sum+=a[i];
		q.push(make_pair(a[i],i));
	}
	inv[1]=1;for(int i=2;i<=sum;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
	int ww=1;
	while(sum)
	{
		int x=q.top().second,w=q.top().first;q.pop();
		ww=1ll*ww*inv[sum]%mod*w%mod*n%mod;
		q.push(make_pair(w-1,x));sum--;
	}
	cout<<ww<<endl;
	return 0;
}

有时候问题不一定非要往复杂想,简单化可能就是正解

T3.路径

被告知是知识点的原题,涉及到斯特林数
这个套路是对这个\(k\)次方展开,把它改成斯特林的形式
假设\(ans_x\)代表每个x到所有点的答案,最后求和再除以二,直接贴柿子
image
所以求出对应的\(\sum C\)就行了
\(f_{i,j}\)表示在\(i\)的子树内对应\(j\)\(\sum\)的答案,利用组合数的性质可以递推
image
然后做一个换根dp就行,注意取模

#include <bits/stdc++.h>
using namespace std;
const int N=1000050;
const int mod=998244353;
inline int read()
{
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x;
}
inline int A(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int P(int x,int y){return x-y>0?x-y:x-y+mod;}
struct node{
	int from,to,next;
}a[2*N];
int head[N],mm=1;
inline void add(int x,int y)
{
	a[mm].from=x;a[mm].to=y;
	a[mm].next=head[x];head[x]=mm++;
}
int f[N][105],g[N][105],n,k;bool v[N];
void dfs1(int x)
{
	v[x]=1;f[x][0]=1;
	for(int i=head[x];i;i=a[i].next)
	{
		int y=a[i].to;
		if(v[y])continue;
		dfs1(y);
		for(int j=1;j<=k;j++)
		 f[x][j]=A(A(f[x][j],f[y][j]),f[y][j-1]);
		f[x][0]=A(f[x][0],f[y][0]);
	}	
}
void dfs2(int x)
{
	v[x]=1;
	for(int i=head[x];i;i=a[i].next)
	{
		int y=a[i].to;
		if(v[y])continue;
		for(int j=0;j<=k;j++)
		{
			int f1=0,f2=0;
			f1=P(P(g[x][j],f[y][j]),((j-1>=0)?f[y][j-1]:0));
			f2=P(((j-1>=0)?P(g[x][j-1],f[y][j-1]):0),((j-2>=0)?f[y][j-2]:0));
			g[y][j]=A(A(f[y][j],f1),f2);
		}
		dfs2(y);
	}
}
int sit[105][105],jc[105];
signed main()
{
	n=read(),k=read();
	for(int i=1;i<n;i++)
	{
		int x=read(),y=read();
		add(x,y);add(y,x);
	}
	dfs1(1);memset(v,0,sizeof(v));	
	for(int i=0;i<=k;i++)g[1][i]=f[1][i];
	dfs2(1);
	sit[0][0]=jc[0]=1;
	for(int i=1;i<=k;i++)
	{
	 	sit[i][0]=0;
	 	for(int j=1;j<=i;j++)
		 sit[i][j]=A(1ll*j*sit[i-1][j]%mod,sit[i-1][j-1]);
		jc[i]=1ll*jc[i-1]*i%mod;
	}
	int ans=0;
	for(int i=1;i<=n;i++)for(int j=0;j<=k;j++)
	 ans=A(ans,1ll*sit[k][j]*jc[j]%mod*g[i][j]%mod);
	cout<<1ll*ans*499122177%mod;
	return 0;
}

有关斯特林的先咕了,等学到了详细写

T4.树

分块好题,dfs序分块+根号分治
暂时没做,学了之后一定要做
吐槽下这数据弱的真实,最大树高25也是醉了

\(upd\ \ on 11.2\)
首先子树里修改就是在dfs序上的一共区间里修改
将所有修改分成\(x<=\sqrt n\)\(x>\sqrt n\)两个部分分别处理
对于前者,\(x\)一共最多有根号个,所以枚举每个深度,将对应深度的修改和所有询问都拿出来
根据模之后的余数的不同,将这些询问和修改分别挂在对应余数的桶中,然后对于每个余数分别处理
这个预处理操作最多枚举\(\sqrt n\)次,每次遍历整个操作序列,这时复杂度是\(n\sqrt n\)
然后开始枚举桶,枚举桶中元素,注意到由于修改不连续,似乎没办法直接做
这里我们的方法是:舍弃全局正确性,只保证询问正确
我们直接对整个区间进行修改,而我们只需要回答这个余数的询问,所以该有贡献的一定有,多加的也没有贡献,不会被算上
由于下个询问就不一样了,所以每个余数做完之后要把刚才的所有修改撤销,反正有影响的都算过了,答案依然对
现在问题是怎么修改查询,发现区间修改有\(n\)个,单点查询有\(m\sqrt n\)个,所以分块做,正好是\(n\sqrt n\)
第二种情况\(x>\sqrt n\)发现一次能修改的深度只有根号种
那么我们对每个深度开桶,存可以修改到他的询问和修改,然后用上面的方法做
然而发现空间会炸,所以考虑优化一下,每次限定\(\sqrt n\)个深度,对这些开桶记录修改询问,这里正好反过来,修改是\(m\sqrt n\),询问是\(n\),所以差分分块,也能保证\(n\sqrt n\)的复杂度
思路确实很好,只不过有亿点难写

#include <bits/stdc++.h>
using namespace std;
#define mp make_pair
#define pb push_back
#define pir pair<int,int>
const int N=300050,M=550;
inline int read()
{
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x;
}
struct node{
	int from,to,next;
}a[2*N];
int head[N],mm=1;
inline void add(int x,int y)
{
	a[mm].from=x;a[mm].to=y;
	a[mm].next=head[x];head[x]=mm++;
}
int n,m,dfn[N],d[N],tot,size[N],mxd=1;
void dfs(int x,int fa)
{
	dfn[x]=++tot;
	for(int i=head[x];i;i=a[i].next)
	{
		int y=a[i].to;
		if(y==fa)continue;
		d[y]=d[x]+1;mxd=max(mxd,d[y]);
		dfs(y,x);size[x]+=size[y];
	}
	size[x]++;
}
struct qu{int id,x,ans;}q[N];
struct cge{int id,p,x,y,z;}c[N];
int op[N],cnt1,cnt2,id[N];
struct cg{int op,id,v;};stack <cg> st;
int b[N],len,s,ll[M],rr[M],bl[N];
int sum[M],w[N];vector <pir> pp[M];
inline void gan1(int l,int r,int v)
{
	for(int i=l;i<=r;i++)
	  w[i]+=v,st.push((cg){1,i,v});
}
inline void gan2(int l,int r,int v)
{
	for(int i=l;i<=r;i++)
	  sum[i]+=v,st.push((cg){2,i,v});	
}
inline void gan3(int p,int v)
{
	sum[bl[p]]+=v;w[p]+=v;
	st.push((cg){1,p,v});
	st.push((cg){2,bl[p],v});
}
inline void gan4(int l,int r,int v)
{
	gan3(l,v);gan3(r+1,-v);
}
inline int get(int p)
{
	int idd=bl[p];int ans=0;
	for(int i=1;i<=idd-1;i++)ans+=sum[i];
	for(int i=ll[idd];i<=p;i++)ans+=w[i];
	return ans;
}
inline void reback()
{
	while(st.size())
	{
		cg ga=st.top();st.pop();
		if(ga.op==1)w[ga.id]-=ga.v;
		else sum[ga.id]-=ga.v;
	}
}
signed main()
{	
	n=read(),m=read();
	for(int i=1;i<n;i++)
	{
		int x=read(),y=read();
		add(x,y);add(y,x);
	}
	d[1]=1;dfs(1,0);
	for(int i=1;i<=m;i++)
	{
		op[i]=read();
		if(op[i]&1)c[++cnt1]=(cge){i,read(),read(),read(),read()},id[i]=cnt1;
		else q[++cnt2]=(qu){i,read()},id[i]=cnt2;
	}
	len=sqrt(n);s=n/len;if(n%len)s++;
	for(int i=1;i<=s;i++)
	{
		ll[i]=(i-1)*len+1,rr[i]=ll[i]+len-1;
		if(i==s)rr[i]=n;
		for(int j=ll[i];j<=rr[i];j++)bl[j]=i;
	}
	int lim=sqrt(n);
	for(int i=1;i<=lim;i++)
	{
		for(int j=0;j<i;j++)pp[j].clear();
		for(int j=1;j<=m;j++)
		{
			int idd=id[j],opp=op[j];
			if(opp&1)
			{
				if(c[idd].x!=i)continue;
				pp[(c[idd].y+d[c[idd].p])%i].pb(mp(opp,idd));
			}
			else pp[d[q[idd].x]%i].pb(mp(opp,idd));
		}	
		for(int j=0;j<i;j++)
		{
			for(int k=0;k<pp[j].size();k++)
			{
				pir ga=pp[j][k];
				int opp=ga.first,idd=ga.second;
				if(opp&1)
				{	
					int l=dfn[c[idd].p],r=l+size[c[idd].p]-1;
					int p1=bl[l],p2=bl[r],v=c[idd].z;
					if(p1==p2)gan1(l,r,v);
					else
					{
						if(l!=ll[p1])gan1(l,rr[p1],v),p1++;
						if(r!=rr[p2])gan1(ll[p2],r,v),p2--;
						if(p1<=p2)gan2(p1,p2,v);
					}
				}
				else
				{
					int p=dfn[q[idd].x];
					q[idd].ans+=w[p]+sum[bl[p]];
				}
			}
			reback();
		}		
	}
	for(int i=1;i<=lim;i++)pp[i].clear();
	int lnn=sqrt(mxd),ss=mxd/lnn;if(mxd%lnn)ss++;
	for(int i=1;i<=ss;i++)
	{
		int pl=(i-1)*lnn+1,pr=pl+lnn-1;
		if(i==ss)pr=mxd;
		for(int j=1;j<=lnn;j++)pp[j].clear();
		for(int j=1;j<=m;j++)
		{
			int opp=op[j],idd=id[j];
			if(opp&1)
			{
				if(c[idd].x<=lim)continue;
				if(d[c[idd].p]+c[idd].y>pr)continue;
				int p=((pr-(d[c[idd].p]+c[idd].y))/c[idd].x)*c[idd].x+d[c[idd].p]+c[idd].y;
				if(p<pl||p>pr)continue;
				pp[p-pl+1].pb(mp(opp,idd));
			}
			else
			{
				if(d[q[idd].x]<pl||d[q[idd].x]>pr)continue;
				pp[d[q[idd].x]-pl+1].pb(mp(opp,idd));
			}
		}
		for(int j=1;j<=lnn;j++)
		{
			for(int k=0;k<pp[j].size();k++)
			{
				pir ga=pp[j][k];
				int opp=ga.first,idd=ga.second;
				if(opp&1)
				{
					int l=dfn[c[idd].p],r=l+size[c[idd].p]-1;
					gan4(l,r,c[idd].z);
				}
				else q[idd].ans+=get(dfn[q[idd].x]);
			}
			reback();
		}
	}
	for(int i=1;i<=cnt2;i++)printf("%d\n",q[i].ans);
	return 0;
}

考试总结

乱搞能力太差,这是一个比较尴尬的缺点,别人会骗到很多分,自己只有暴力
写的时候一定要专注,不要轻敌,细节把握好,记得检查

posted @ 2021-09-15 07:10  D'A'T  阅读(51)  评论(0编辑  收藏  举报