首页 > 其他分享 >csp-s模拟10

csp-s模拟10

时间:2024-10-08 18:23:14浏览次数:7  
标签:10 limits int sum pos csp 100010 ll 模拟

csp-s模拟10

\(T1\) T3673. 欧几里得的噩梦 \(0pts\)

  • 部分分
    • \(0 \%\) :状压加枚举子集。
    • \(20 \%\) :线性基暴力做。
  • 正解

\(T2\) T3672. 清扫 \(6pts\)

  • 原题: [AGC010C] Cleaning

  • 钦定根节点 \(rt\) 的度数 \(\ge 2\) ,所以需要特判 \(n=2\) 的情况。

  • 部分分

    • 未知 \(pts\) :
      • 等价于查询是否存在一种进行若干次点差分方式,对于差分数组 \(d\) 满足 \(\forall x \in [1,n],a_{x}=\sum\limits_{y \in Subtree(x)}d_{y}\) 。
      • 直接进行高斯消元时间复杂度不可接受,手动解出 \(d_{x}=a_{x}-\sum\limits_{y \in Son(x)}a_{y}\) 。
      • 又因为对于非叶子节点的 \(x\) 其 \(d_{x}\) 由 \(x\) 作为 \(fa_{\operatorname{LCA}(u,v)}\) 和 \(x\) 作为 \(\operatorname{LCA}(u,v)\) 两部分的贡献组成,设它们分别为 \(f_{x},g_{x}\) ,有 \(f_{x}+g_{x}=d_{x}\) 。
      • 不难得到 \(f_{x}=\sum\limits_{y \in Son(x)}g_{y}\) ,即 \(d_{x}=g_{x}+\sum\limits_{y \in Son(x)}g_{y}\) ,类似 \(\{ d \}\) 的求法再次手动求出 \(\{ f \},\{ g \}\) 。
      • 问题就转化为是否存在一种构造方式使得点差分时叶子节点 \(x\) 恰好访问了 \(d_{x}\) 次,而非叶子节点 \(y\) 作为任意两个叶子节点的 \(\operatorname{LCA}\) 被访问了 \(-g_{y}\) 遍。
      • 赛时因为不知道怎么判断,所以只写了最基本的 \(-\sum\limits_{i=1}^{n}[du_{i} \ne 1] \times g_{i}=\sum\limits_{i=1}^{n}[du_{i}=1] \times d_{i}\) ,没过大样例。
  • 正解

    • \(\{ f \}\) 数组好像没啥用,直接扔掉。并令 \(\{ g \}\) 都乘以 \(-1\) 表示作为 \(\operatorname{LCA}(u,v)\) 的次数,此时 \(g_{x}=-d_{x}-\sum\limits_{y \in Son(x)}g_{y}\) ,令叶子节点的 \(g=0\) 。
    • 令 \(f_{x}\) 表示 \(x\) 子树内叶子节点向上拓展的总路径条数(差分剩下的),有 \(f_{x}=\begin{cases} a_{x} & du_{x}=1 \\ -2g_{x}+\sum\limits_{y \in Son(x)}f_{y} & du_{x} \ne 1 \end{cases}\) 。
    • 考虑此时如何判断有解。
      • \(g_{x} \ge 0\)
      • \(f_{rt}=0\)
      • \(0 \le f_{x} \le a_{x} \land \sum\limits_{y \in Son(x)}f_{y}- \max\limits_{y \in Son(x)}\{ f_{y} \} \ge g_{x}\)
        • 前者隐含了 \(\frac{\sum\limits_{y \in Son(x)}f_{y}}{2} \ge g_{x}\) 的条件。
        • 后者的感性理解是若 \(\max\limits_{y \in Son(x)}\{ f_{y} \} > \frac{\sum\limits_{y \in Son(x)}f_{y}}{2}\) ,则合并次数在满足 \(f_{y}\) 最大的 \(y\) 子树和其他子树进行合并时取到最多 \(\sum\limits_{y \in Son(x)}f_{y}- \max\limits_{y \in Son(x)}\{ f_{y} \}\) ;否则两两进行匹配,合并次数为 \(\frac{\sum\limits_{y \in Son(x)}f_{y}}{2}\) 。
    • 证明有点抽象,感性理解吧。
    点击查看代码
    struct node
    {
    	ll nxt,to;
    }e[200010];
    ll head[200010],du[200010],a[200010],d[200010],f[200010],g[200010],cnt=0;
    void add(ll u,ll v)
    {
    	cnt++;
    	e[cnt].nxt=head[u];
    	e[cnt].to=v;
    	head[u]=cnt;
    }
    void dfs(ll x,ll fa)
    {
    	ll sum=0,maxx=0;
    	d[x]=a[x];
    	if(du[x]==1)
    	{
    		f[x]=a[x];
    		return;
    	}
    	for(ll i=head[x];i!=0;i=e[i].nxt)
    	{
    		if(e[i].to!=fa)
    		{
    			dfs(e[i].to,x);
    			d[x]-=a[e[i].to];
    			g[x]-=g[e[i].to];
    			sum+=f[e[i].to];
    			maxx=max(maxx,f[e[i].to]);
    		}
    	}
    	g[x]-=d[x];
    	f[x]=-2*g[x]+sum;
    	if(g[x]<0||f[x]<0||f[x]>a[x]||sum-maxx<g[x])
    	{
    		cout<<"NO"<<endl;
    		exit(0);
    	}
    }
    int main()
    {
    	freopen("tree.in","r",stdin);
    	freopen("tree.out","w",stdout);
    	ll n,u,v,rt,i;
    	cin>>n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    	}
    	for(i=1;i<=n-1;i++)
    	{
    		cin>>u>>v;
    		du[u]++;
    		du[v]++;
    		add(u,v);
    		add(v,u);
    	}
    	if(n==2)
    	{
    		if(a[1]==a[2])
    		{
    			cout<<"YES"<<endl;
    		}
    		else
    		{
    			cout<<"NO"<<endl;
    		}
    	}
    	else
    	{
    		for(i=1;i<=n;i++)
    		{
    			if(du[i]>=2)
    			{
    				rt=i;
    				break;
    			}
    		}
    		dfs(rt,0);
    		if(f[rt]==0)
    		{
    			cout<<"YES"<<endl;
    		}
    		else
    		{
    			cout<<"NO"<<endl;
    		}
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

\(T3\) T1072. 购物 \(20pts\)

  • 部分分
    • 子任务 \(1,3\) :背包处理出能拼出来的商品价格,然后写一个静态推平全局查询的数据结构即可。

      点击查看代码
      struct ODT
      {
      	struct node
      	{
      		ll l,r;
      		mutable ll col;
      		bool operator < (const node &another) const
      		{
      			return l<another.l;
      		}
      	};
      	set<node>s;
      	void init()
      	{
      		s.insert((node){0,1000000000010,0});
      	}
      	set<node>::iterator split(ll pos)
      	{
      		set<node>::iterator it=s.lower_bound((node){pos,0,0});
      		if(it!=s.end()&&it->l==pos)
      		{
      			return it;
      		}
      		it--;
      		if(it->r<pos)
      		{
      			return s.end();
      		}
      		ll l=it->l,r=it->r,col=it->col;
      		s.erase(it);
      		s.insert((node){l,pos-1,col});
      		return s.insert((node){pos,r,col}).first;
      	}
      	void assign(ll l,ll r,ll col)
      	{
      		set<node>::iterator itr=split(r+1),itl=split(l);
      		s.erase(itl,itr);
      		s.insert((node){l,r,col});
      	}
      	ll query(ll l,ll r)
      	{
      		set<node>::iterator itr=split(r+1),itl=split(l);
      		ll ans=0;
      		for(set<node>::iterator it=itl;it!=itr;it++)
      		{
      			ans+=(it->col==1)*(it->r-it->l+1);
      		}
      		return ans;
      	}
      }O;
      ll a[100010];
      bool f[1000010];
      void dfs(ll pos,ll n,ll sum)
      {
      	if(pos==n+1)
      	{
      		if(sum!=0)
      		{
      			O.assign(ceil(sum/2.0),sum,1);
      		}
      	}
      	else
      	{
      		dfs(pos+1,n,sum+a[pos]);
      		dfs(pos+1,n,sum);
      	}
      }
      int main()
      {
      	freopen("buy.in","r",stdin);
      	freopen("buy.out","w",stdout);
      	ll n,m=0,i,j;
      	cin>>n;
      	for(i=1;i<=n;i++)
      	{
      		cin>>a[i];
      		m+=a[i];
      	}
      	O.init();
      	if(m<=1000000)
      	{
      		f[0]=1;
      		for(i=1;i<=n;i++)
      		{
      			for(j=m;j>=a[i];j--)
      			{
      				f[j]|=f[j-a[i]];
      			}
      		}
      		for(i=1;i<=m;i++)
      		{
      			if(f[i]==1)
      			{
      				O.assign(ceil(i/2.0),i,1);
      			}
      		}
      	}
      	else
      	{
      		dfs(1,n,0);
      	}
      	cout<<O.query(0,1000000000000)<<endl;
      	fclose(stdin);
      	fclose(stdout);
      	return 0;
      }
      
  • 正解

\(T4\) T1042. ants \(20pts\)

  • 弱化版: BZOJ4358 permu
  • 部分分
    • \(20pts\) :枚举值域起点,时间复杂度为 \(O(nm)\) 。

      点击查看代码
      int a[100010],pos[100010],vis[100010];
      int main()
      {
      	freopen("ants.in","r",stdin);
      	freopen("ants.out","w",stdout);
      	int n,m,l,r,ans;
      	scanf("%d%d",&n,&m);
      	for(int i=1;i<=n;i++)
      	{
      		scanf("%d",&a[i]);
      		pos[a[i]]=i;
      	}
      	for(int j=1;j<=m;j++)
      	{
      		scanf("%d%d",&l,&r);
      		ans=0;
      		for(int i=1;i<=n;i++)
      		{
      			if(vis[i]==0)
      			{
      				int k;
      				for(k=i;l<=pos[k]&&pos[k]<=r;k++)
      				{
      					vis[k]=1;
      				}
      				ans=max(ans,k-i);
      			}
      			vis[i]=0;
      		}
      		printf("%d\n",ans);
      	}
      	fclose(stdin);
      	fclose(stdout);
      	return 0;
      }
      
    • \(50pts\) :同 BZOJ4358 permu 的做法,时间复杂度为 \(O(n \sqrt{m} \log n)\) 。因普通版线段树常数过大所以无法通过。

      点击查看代码
      int a[400000],ans[400000],L[400000],R[400000],pos[400000],klen,ksum;
      struct ask
      {
      	int l,r,id;
      }q[400000];
      bool q_cmp(ask a,ask b)
      {
      	return (pos[a.l]==pos[b.l])?((pos[a.l]%2==1)?(a.r<b.r):(a.r>b.r)):(a.l<b.l);
      }
      struct SegmentTree
      {
      	int l,r,maxl,maxr,ans;
      }tree[400000];
      int lson(int x)
      {
      	return x*2;
      }
      int rson(int x)
      {
      	return x*2+1;
      }
      void pushup(int rt)
      {
      	tree[rt].maxl=tree[lson(rt)].maxl+(tree[lson(rt)].maxl==tree[lson(rt)].r-tree[lson(rt)].l+1)*tree[rson(rt)].maxl;
      	tree[rt].maxr=tree[rson(rt)].maxr+(tree[rson(rt)].maxr==tree[rson(rt)].r-tree[rson(rt)].l+1)*tree[lson(rt)].maxr;
      	tree[rt].ans=max(max(tree[lson(rt)].ans,tree[rson(rt)].ans),tree[lson(rt)].maxr+tree[rson(rt)].maxl);
      }
      void build(int rt,int l,int r)
      {
      	tree[rt].l=l;
      	tree[rt].r=r;
      	if(l==r)
      	{
      		return;
      	}
      	int mid=(l+r)/2;
      	build(lson(rt),l,mid);
      	build(rson(rt),mid+1,r);
      	pushup(rt);
      }
      void update(int rt,int pos,int ans)
      {
      	if(tree[rt].l==tree[rt].r)
      	{
      		tree[rt].ans=tree[rt].maxl=tree[rt].maxr=ans;
      		return;
      	}
      	else
      	{
      		int mid=(tree[rt].l+tree[rt].r)/2;
      		if(mid>=pos)
      		{
      			update(lson(rt),pos,ans);
      		}
      		else
      		{
      			update(rson(rt),pos,ans);
      		}
      		pushup(rt);
      	}
      }
      SegmentTree query(int rt,int l,int r)
      {
      	if(l<=tree[rt].l&&tree[rt].r<=r)
      	{
      		return tree[rt];
      	}
      	else
      	{
      		int mid=(tree[rt].l+tree[rt].r)/2;
      		if(r<=mid)
      		{
      			return query(lson(rt),l,r);
      		}
      		else
      		{
      			if(l>mid)
      			{
      				return query(rson(rt),l,r);
      			}
      			else
      			{
      				SegmentTree p=query(lson(rt),l,r),q=query(rson(rt),l,r),num;
      				num.maxl=p.maxl+(p.maxl==p.r-p.l+1)*q.maxl;
      				num.maxr=q.maxr+(q.maxr==q.r-q.l+1)*p.maxr;
      				num.ans=max(max(p.ans,q.ans),p.maxr+q.maxl);
      				return num;
      			}
      		}
      	}
      }
      void init(int n,int m)
      {
      	klen=n/sqrt(m)+1;
      	ksum=500;
      	for(int i=1;i<=ksum;i++)
      	{
      		L[i]=R[i-1]+1;
      		R[i]=R[i-1]+klen;
      	}
      	if(R[ksum]<n)
      	{
      		ksum++;
      		L[ksum]=R[ksum-1]+1;
      		R[ksum]=n;
      	}
      	for(int i=1;i<=ksum;i++)
      	{
      		for(int j=L[i];j<=R[i];j++)
      		{
      			pos[j]=i;
      		}
      	}
      }
      void add(int x)
      {
      	update(1,a[x],1);
      }
      void del(int x)
      {
      	update(1,a[x],0);
      }
      int main()
      {
      	freopen("ants.in","r",stdin);
      	freopen("ants.out","w",stdout);
      	int n,m,l=1,r=0,i;
      	cin>>n>>m;
      	for(i=1;i<=n;i++)
      	{
      		cin>>a[i];
      	}
      	build(1,1,n);
      	init(n,m);
      	for(i=1;i<=m;i++)
      	{
      		cin>>q[i].l>>q[i].r;
      		q[i].id=i;
      	}
      	sort(q+1,q+1+m,q_cmp);
      	for(i=1;i<=m;i++)
      	{
      		while(l>q[i].l)
      		{
      			l--;
      			add(l);
      		}
      		while(r<q[i].r)
      		{
      			r++;
      			add(r);
      		}
      		while(l<q[i].l)
      		{
      			del(l);
      			l++;
      		}
      		while(r>q[i].r)
      		{
      			del(r);
      			r--;
      		}
      		ans[q[i].id]=query(1,1,n).ans;
      	}
      	for(i=1;i<=m;i++)
      	{
      		cout<<ans[i]<<endl;
      	}
      	return 0;
      }
      
  • 正解
    • 考虑只加不减莫队。加入一个数 \(x\) 时判断 \(x-1,x+1\) 是否已经加入并连一条边,接着链表或可撤销并查集维护即可。

      点击查看代码
      struct ask
      {
      	int l,r,id;
      }q[100010];
      int a[100010],b[100010],ans[100010],L[100010],R[100010],pos[100010],vis[100010],klen,ksum;
      bool q_cmp(ask a,ask b)
      {
      	return (pos[a.l]==pos[b.l])?(a.r<b.r):(a.l<b.l);
      }
      void init(int n,int m)
      {
      	klen=n/sqrt(m)+1;
      	ksum=n/klen;
      	for(int i=1;i<=ksum;i++)
      	{
      		L[i]=R[i-1]+1;
      		R[i]=R[i-1]+klen;
      	}
      	if(R[ksum]<n)
      	{
      		ksum++;
      		L[ksum]=R[ksum-1]+1;
      		R[ksum]=n;
      	}
      	for(int i=1;i<=ksum;i++)
      	{
      		for(int j=L[i];j<=R[i];j++)
      		{
      			pos[j]=i;
      		}
      	}
      }
      struct DSU
      {
      	struct quality
      	{
      		int id,fa,siz;
      	};
      	stack<quality>s;
      	int fa[100010],siz[100010];
      	void init(int n)
      	{
      		for(int i=1;i<=n;i++)
      		{
      			fa[i]=i;
      			siz[i]=1;
      		}
      	}
      	int find(int x)
      	{
      		return (fa[x]==x)?x:find(fa[x]);
      	}
      	void merge(int x,int y,int &sum)
      	{
      		x=find(x);
      		y=find(y);
      		if(x!=y)
      		{
      			if(siz[x]<siz[y])
      			{
      				swap(x,y);
      			}
      			s.push((quality){x,fa[x],siz[x]});  
      			s.push((quality){y,fa[y],siz[y]});
      			fa[y]=x;
      			siz[x]+=siz[y];
      			sum=max(sum,siz[x]);
      		}
      	}
      	void split(int tmp)
      	{
      		while(s.empty()==0&&s.size()>tmp)
      		{
      			fa[s.top().id]=s.top().fa;
      			siz[s.top().id]=s.top().siz;
      			s.pop();
      		}
      	}
      }D;
      void add(int x,int &sum)
      {
      	vis[x]=1;
      	if(vis[x-1]==1)
      	{
      		D.merge(x,x-1,sum);
      	}
      	if(vis[x+1]==1)
      	{
      		D.merge(x,x+1,sum);
      	}
      }
      int main()
      {
      	freopen("ants.in","r",stdin);
      	freopen("ants.out","w",stdout);
      	int n,m,l=1,r=0,sum,tmp=1,num,lastblock=0,i,j;
      	cin>>n>>m;
      	for(i=1;i<=n;i++)
      	{
      		cin>>a[i];
      	}
      	for(i=1;i<=m;i++)
      	{
      		cin>>q[i].l>>q[i].r;
      		q[i].id=i;
      	}
      	init(n,m);
      	sort(q+1,q+1+m,q_cmp);
      	D.init(n);
      	for(i=1;i<=m;i++)
      	{
      		if(pos[q[i].l]==pos[q[i].r])
      		{
      			sum=num=1;
      			for(j=q[i].l;j<=q[i].r;j++)
      			{
      				b[j]=a[j];
      			}
      			sort(b+q[i].l,b+q[i].r+1);
      			for(j=q[i].l+1;j<=q[i].r;j++)
      			{
      				num=(b[j-1]==b[j]-1)*num+1;
      				sum=max(sum,num);
      			}
      		}
      		else
      		{
      			if(lastblock!=pos[q[i].l])
      			{
      				while(r>R[pos[q[i].l]])
      				{
      					vis[a[r]]=0;
      					r--;
      				}
      				while(l<R[pos[q[i].l]]+1)
      				{
      					vis[a[l]]=0;
      					l++;
      				}
      				tmp=1;
      				r=R[pos[q[i].l]];
      				l=R[pos[q[i].l]]+1;
      				lastblock=pos[q[i].l];
      				D.split(0);
      			}
      			while(r<q[i].r)
      			{
      				r++;
      				add(a[r],tmp);
      			}
      			sum=tmp;
      			num=D.s.size();
      			while(l>q[i].l)
      			{
      				l--;
      				add(a[l],sum);
      			}
      			D.split(num);
      			while(l<R[pos[q[i].l]]+1)
      			{   
      				vis[a[l]]=0;
      				l++;
      			}
      		}
      		ans[q[i].id]=sum;
      	}
      	for(i=1;i<=m;i++)
      	{
      		cout<<ans[i]<<endl;
      	}
      	fclose(stdin);
      	fclose(stdout);
      	return 0;
      }
      

总结

  • 感觉思维越来越不行了,需要稍微跳跃点的就反应不过来了。
  • \(T2\) 只判了叶子节点的 \(d\) 忘判非叶子节点的 \(g\) 了,挂了 \(20pts\) 。
  • \(T3\) 只记得写子任务 \(3\) 的超大背包部分分了,忘了写子任务 \(1\) 的正常背包部分分了,挂了 \(30pts\) 。
  • \(T4\) 赛时没记得做过原题,我是不是该拉出去毙了。

标签:10,limits,int,sum,pos,csp,100010,ll,模拟
From: https://www.cnblogs.com/The-Shadow-Dragon/p/18452249

相关文章

  • 10/8
    慧鱼机电实训理论与实践结合:通过实训,我们能够将课堂上学到的理论知识应用于实际操作中,加深对机电系统的理解。团队合作的重要性:在实训过程中,往往需要与同学们密切合作,分工合作不仅提高了效率,也培养了团队意识和沟通能力。解决问题的能力:在面对设备故障或调试难题时,我学会了冷......
  • 202410-Notes for reading
    TDB1.Gravityexperimentswithradiopulsarshttps://ui.adsabs.harvard.edu/abs/2024LRR....27....5F/abstract2.PhD,Porayko,NataliyaKonstantinovna_2019_ProbingtheInterstellarMediumandDarkMatterwithPulsars5.PhD,2020,NataliyaK.PoraykoProbin......
  • 20222310 2024-2025-1 《网络与系统攻防技术》实验一实验报告
    一、实验内容1.实验目标本次实验的对象是一个名为pwn1的linux可执行文件。该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实验的目标就是想......
  • csp-s模拟10
    rank31,垫底了,T10pts,T218pts,T30pts,T450pts状态有点不好,策略有问题,T4是可以切的,但是不知道为什么弃了。T1不会线性基寄。T3奇怪结论题,T2结论题。在猜结论上还是不行。T1欧几里得的噩梦用到了线性基线性无关的性质,将两个数连边,把环去掉,并查集判断即可。统计答案用快速......
  • Linux csplit命令
    csplit命令在Linux中用于将文件分割成多个部分,基于指定的模式或固定数量的行。与split命令不同,csplit允许更复杂的分割条件,例如基于正则表达式匹配或特定字符的出现次数。基本语法csplit[选项]文件名模式文件名:要分割的文件。模式:分割文件的依据,可以是正则表达式或数字。......
  • P10641 BZOJ3252 攻略
    题目链接简要题意给定一个有\(n\)个结点的树,树有点权且点权为正整数。现选取\(k\)条从根结点出发到叶子结点的简单路径,求这些路径的并集上所有结点的点权之和的最大值。主要算法贪心,树链剖分,(线段树合并)思路一个显然的贪心,每次选一点点权和最大的链,再讲这条链清为0。正......
  • 【1024程序猿节】IT人#摸鱼计划#,多重奖励等你来拿!
    10月摸鱼计划如期而至,全新上线3款活动任务,还有多重奖励等你来拿!【活动时间】发文时间:2024年10月8日—2024年10月31日【活动任务】以下任务福利可同享!!同时,我们为大家整理了容易被百度收录的关键词,当你写作的时候,可以直接选择热点且擅长的关键词进行博文创作。 直达热点关键词库>>任......
  • Day1 备战CCF-CSP练习
    Day1201403-1问题描述有$N$个非零且各不相同的整数。请你编一个程序求出它们中有多少对相反数($a$和$-a$为一对相反数)。输入格式第一行包含一个正整数$N$。$(1≤N≤500)$。第二行为$N$个用单个空格隔开的非零整数,每个数的绝对值不超过$1000$,保证这些整数各......
  • 2024年10月8日大盘行情
    2024年5月中旬开始,大盘一直下跌,每天的交易额缩减到5000亿左右,人气低迷。2024年9月20日左右,出台了一系列提振经济和股市的政策,十一假期前的一周,大盘快速拉升,一周时间走完了半年的行情。很多人担心节后第一天会下杀,节前清空了仓位。节后第一天几乎涨停开盘,然后盘中下杀,最终收盘有所......
  • mfc100u.dll丢失找不到,win10电脑mfc100u.dll缺失的解决方法
    Mfc100u.dll是MicrosoftVisualStudio2010的一个重要动态链接库文件,主要用于支持基于MicrosoftFoundationClasses(MFC)的应用程序运行。当在Windows10系统中遇到“找不到Mfc100u.dll”或“Mfc100u.dll丢失”等错误提示时,意味着某些应用程序可能无法正常启动或运行。本文......