CSP2024 前集训:多校A层冲刺NOIP2024模拟赛07

前言

image

image

T1 freopen 输入输出打反了!?!?!?!!然后我需要跑三遍生成树(两遍就行),别人只需要跑一遍感觉做法好劣啊。

T2 大模拟赛时没调出来。

T3 本来会曼哈顿距离与切比雪夫距离的相互转化,赛时竟然没有想到;因为常数巨大,OJ 上开了 \(5s\) 实现,accoders 甚至开了 \(7s\),结果双 \(\log\) 还是跑不过去,加了取模优化 accoders 过了,OJ 上只能 \(90pts\),正解单 \(\log\) 线段树合并都是擦边过,看在你部分分给得足的份上原谅你了。

T4 抽象玩意咕了咕了。

T1 限速

最优策略只可能出自于两种情况:

  • 所选中所有权值 \(<k\),答案为 \(k-\) 所选出的最大权值。
  • 所选中存在权值 \(\ge k\) 的权值,答案为这些权值 \(-k\) 的和。

两种情况分别跑一遍最小生成树即可。

对于第一种对于所有权值 \(<k\) 的边按权值从大到小选,此时可能无解,此时另一种情况一定有解。

对于第二种,在所有权值 \(>k\) 的中强制选择权值最小的一条边,再将所有边按照权值从小到大选。

两种答案取 \(\min\) 即可。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=2e5+10;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,m,k,tot,last,f[N]; ll ans,sum; bitset<N>vis;
struct aa {int x,y,w;}e[N];
int find(int x) {return x==f[x]?x:f[x]=find(f[x]);}
signed main()
{
	freopen("speed.in","r",stdin),freopen("speed.out","w",stdout);
	read(n,m,k); for(int i=1;i<=n;i++) f[i]=i;
	for(int i=1,x,y,z;i<=m;i++) read(x,y,z),e[i]={x,y,z-k};
	sort(e+1,e+1+m,[](aa a,aa b){return a.w<b.w;});
	for(int i=1;i<=m;i++)
	{
		int x=find(e[i].x),y=find(e[i].y);
		if(x==y) continue; f[x]=y,tot++,vis.set(i);
		if(tot==n-1) {last=i; break;}
	}
	if(e[last].w>=0)
	{for(int i=last;i>=1;i--) if(vis[i]&&e[i].w>=0) ans+=e[i].w;}
	else
	{
		ans=-e[last].w; bool flag=0;
		for(int i=1;i<=n;i++) f[i]=i;
		for(int i=last+1;i<=m;i++) if(e[i].w>=0)
		{
			if(e[i].w<ans)
				f[find(e[i].x)]=find(e[i].y),tot=1,flag=1,sum=e[last=i].w;
			else break;
		}
		if(flag)
		{
			if(tot==n-1) return write(sum),0;
			for(int i=1;i<=m;i++)
			{
				int x=find(e[i].x),y=find(e[i].y);
				if(x==y) continue; f[x]=y,tot++,sum+=max(0,e[i].w);
				if(tot==n-1) {last=i; break;}
			}
			ans=min(ans,sum);
		}
		for(int i=1;i<=n;i++) f[i]=i;
		if(!flag) last=m+1; sum=-e[last-1].w,tot=0;
		for(int i=last-1;i;i--)
		{
			int x=find(e[i].x),y=find(e[i].y);
			if(x==y) continue; f[x]=y,tot++;
			if(tot==n-1) break;
		}
		if(tot==n-1) ans=min(ans,sum);
	}
	write(ans);
}

T2 酒鬼

大模拟不想写题解了啊啊啊,扔到 set 里,根据相邻的位移减时间差必须相同判无解。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
#define mkp make_pair
#define fi first
#define se second
using namespace std;
const int N=2e5+10,inf=1e9+10;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,m,mx=inf,tim=inf,last=-1; char op[4]; bool bad; set<pair<int,int> >s;
signed main()
{
	freopen("drunkard.in","r",stdin),freopen("drunkard.out","w",stdout);
	read(n,m); for(int x,y;m;m--)
	{
		scanf("%s",op);
		if(bad) {if(op[1]=='l') read(x,y); else puts("bad");}
		else if(op[1]=='l')
		{
			read(x,y); if(bad|=(x-1>y)) continue;
			if(x>1) tim=min(tim,y),mx=min(mx,y-x+1);
			auto it=s.insert(mkp(y,x)).fi,nxt=next(it);
			if(it!=s.begin())
			{
				auto pre=prev(it);
				if(bad|=abs(pre->se-x)>y-pre->fi) continue;
				last=(nxt!=s.end()&&nxt->fi==last)?-1:last;
				last=(y>last&&((pre->fi-pre->se)&1)!=((y-x)&1))?y:last;
			}
			if(nxt!=s.end())
			{
				if(bad|=abs(nxt->se-x)>nxt->fi-y) continue;
				last=(nxt->fi>last&&((nxt->fi-nxt->se)&1)!=((y-x)&1))?nxt->fi:last;
			}
			bad|=(last>tim);
		}
		else if(op[1]=='i')
		{
			if(last==-1) write(s.size()?((s.begin()->fi-s.begin()->se+1)&1):0),puts("");
			else 
			{
				auto it=--s.lower_bound(mkp(last,0));
				write(min(it->fi+1,last)),puts("");
			}
		}
		else if(mx==inf) puts("inf"); else write(mx),puts("");
	}
}

T3 距离

  • 部分分 \(70pts\):对于每个点 \(O(n)\) 计算他的贡献,总复杂度 \(O(n^2)\)

  • 正解 \(80\sim 100pts\)

    考虑切比雪夫距离转曼哈顿距离,同时 \(\min\)\(\max\),有 \(a+b=\max(a,b)+\min(a,b)\)\((x_1,y_1),(x_2,y_2)\) 两点切比雪夫距离等于 \((\dfrac{x_1+y_1}{2},\dfrac{x_1-y_1}{2}),(\dfrac{x_2+y_2}{2},\dfrac{x_2-y_2}{2})\) 两点曼哈顿距离。

    然后树上启发式合并套树状数组跑就行了,因为树状数组下标是权值所以要离散化,最后答案要 \(\times 2\),不妨把直接把 \(a_i,b_i\)\(\times 2\),还省了求 \(2\) 的逆元了。

    点击查看代码
    #include<bits/stdc++.h>
    #define ll long long
    #define endl '\n'
    #define sort stable_sort
    #define pb push_back
    #define mkp make_pair
    #define fi first
    #define se second
    #define lowbit(x) (x&-x)
    using namespace std;
    const int N=5e5+10,P=1e9+7;
    #define LOCAL
    namespace IO{
    	#ifdef LOCAL
    	FILE*Fin(fopen("distance.in","r")),*Fout(fopen("distance.out","w"));
    	#else
    	FILE*Fin(stdin),*Fout(stdout);
    	#endif
    	class qistream{static const size_t SIZE=1<<16,BLOCK=64;FILE*fp;char buf[SIZE];int p;public:qistream(FILE*_fp=stdin):fp(_fp),p(0){fread(buf+p,1,SIZE-p,fp);}void flush(){memmove(buf,buf+p,SIZE-p),fread(buf+SIZE-p,1,p,fp),p=0;}qistream&operator>>(char&x){x=getch();while(isspace(x))x=getch();return*this;}template<class T>qistream&operator>>(T&x){x=0;p+BLOCK>=SIZE?flush():void();bool flag=false;for(;!isdigit(buf[p]);++p)flag=buf[p]=='-';for(;isdigit(buf[p]);++p)x=x*10+buf[p]-'0';x=flag?-x:x;return*this;}char getch(){p+BLOCK>=SIZE?flush():void();return buf[p++];}qistream&operator>>(char*str){char ch=getch();while(ch<=' ')ch=getch();int i=0;for(;ch>' ';++i,ch=getch())str[i]=ch;str[i]='\0';return*this;}}qcin(Fin);
    	class qostream{static const size_t SIZE=1<<16,BLOCK=64;FILE*fp;char buf[SIZE];int p;public:qostream(FILE*_fp=stdout):fp(_fp),p(0){}~qostream(){fwrite(buf,1,p,fp);}void flush(){fwrite(buf,1,p,fp),p=0;}template<class T>qostream&operator<<(T x){int len=0;p+BLOCK>=SIZE?flush():void();x<0?(x=-x,buf[p++]='-'):0;do buf[p+len]=x%10+'0',x/=10,++len;while(x);for(int i=0,j=len-1;i<j;++i,--j)std::swap(buf[p+i],buf[p+j]);p+=len;return*this;}qostream&operator<<(char x){putch(x);return*this;}void putch(char ch){p+BLOCK>=SIZE?flush():void();buf[p++]=ch;}qostream&operator<<(char*str){for(int i=0;str[i];++i)putch(str[i]);return*this;}qostream&operator<<(const char*s){for(int i=0;s[i];++i)putch(s[i]);return*this;}}qcout(Fout);
    }
    #define cin IO::qcin
    #define cout IO::qcout
    int n,tot,a[N],b[N],va[N],vb[N],sz[N],id[N],dfn[N],son[N],cnt[4],pos[4][N],bk[4][N];
    ll ans[N]; vector<int>e[N];
    inline int mod(int x,int y) {x+=y; return x>=P?x-P:x;}
    struct aa
    {
    	int c1[N],c2[N];
    	void add(int x,int d)
    	{for(;x<=n;x+=lowbit(x)) c1[x]=mod(c1[x],d),c2[x]++;}
    	void del(int x,int d)
    	{for(;x<=n;x+=lowbit(x)) c1[x]=mod(c1[x],P-d),c2[x]--;}
    	pair<ll,int> ask(int x)
    	{
    		pair<ll,int>res=mkp(0,0);
    		for(;x;x-=lowbit(x)) res.fi=mod(res.fi,c1[x]),res.se+=c2[x];
    		return res;
    	}
    	pair<ll,int> ask(int l,int r)
    	{auto x=ask(l-1),y=ask(r); return mkp(mod(y.fi,P-x.fi),y.se-x.se);}
    }t[4];
    inline void dfs1(int x,int fa)
    {
    	sz[id[dfn[x]=++tot]=x]=1; for(int y:e[x]) if(y!=fa) 
    		dfs1(y,x),sz[x]+=sz[y],son[x]=sz[y]>sz[son[x]]?y:son[x];
    }
    inline void calc(int x,int y)
    {
    	auto tmp=t[0].ask(a[y]-1);
    	ans[x]=mod(ans[x],mod(1ll*pos[0][a[y]]*tmp.se%P,P-tmp.fi));
    	tmp=t[0].ask(a[y]+1,cnt[0]);
    	ans[x]=mod(ans[x],mod(tmp.fi,P-1ll*pos[0][a[y]]*tmp.se%P));
    	tmp=t[1].ask(b[y]-1);
    	ans[x]=mod(ans[x],mod(1ll*pos[1][b[y]]*tmp.se%P,P-tmp.fi));
    	tmp=t[1].ask(b[y]+1,cnt[1]);
    	ans[x]=mod(ans[x],mod(tmp.fi,P-1ll*pos[1][b[y]]*tmp.se%P));
    	tmp=t[2].ask(va[y]-1);
    	ans[x]=mod(ans[x],P-mod(1ll*pos[2][va[y]]*tmp.se%P,P-tmp.fi));
    	tmp=t[2].ask(va[y]+1,cnt[2]);
    	ans[x]=mod(ans[x],P-mod(tmp.fi,P-1ll*pos[2][va[y]]*tmp.se%P));
    	tmp=t[3].ask(vb[y]-1);
    	ans[x]=mod(ans[x],P-mod(1ll*pos[3][vb[y]]*tmp.se%P,P-tmp.fi));
    	tmp=t[3].ask(vb[y]+1,cnt[3]);
    	ans[x]=mod(ans[x],P-mod(tmp.fi,P-1ll*pos[3][vb[y]]*tmp.se%P));
    }
    inline void insert(int y)
    {
    	t[0].add(a[y],pos[0][a[y]]),t[1].add(b[y],pos[1][b[y]]);
    	t[2].add(va[y],pos[2][va[y]]),t[3].add(vb[y],pos[3][vb[y]]);
    }
    inline void erase(int y)
    {
    	t[0].del(a[y],pos[0][a[y]]),t[1].del(b[y],pos[1][b[y]]);
    	t[2].del(va[y],pos[2][va[y]]),t[3].del(vb[y],pos[3][vb[y]]);
    }
    inline void dfs2(int x,int fa,bool flag)
    {
    	for(int y:e[x]) if(y!=fa&&y!=son[x]) dfs2(y,x,0),ans[x]=mod(ans[x],ans[y]);
    	if(son[x]) dfs2(son[x],x,1),ans[x]=mod(ans[x],ans[son[x]]);
    	for(int y:e[x]) if(y!=fa&&y!=son[x])
    	{
    		for(int i=dfn[y],z;i<=dfn[y]+sz[y]-1;i++) calc(x,id[i]);
    		for(int i=dfn[y],z;i<=dfn[y]+sz[y]-1;i++) insert(id[i]);
    	}
    	calc(x,x),insert(x);
    	if(!flag) for(int i=dfn[x],z;i<=dfn[x]+sz[x]-1;i++) erase(id[i]);
    }
    signed main()
    {
    	cin>>n; for(int i=1,x,y;i<n;i++) cin>>x>>y,e[x].pb(y),e[y].pb(x);
    	dfs1(1,0); for(int i=1;i<=n;i++)
    	{
    		cin>>a[i]>>b[i],bk[2][i]=va[i]=a[i]+b[i],bk[3][i]=vb[i]=a[i]-b[i];
    		bk[0][i]=(a[i]<<=1),bk[1][i]=(b[i]<<=1);
    	}
    	sort(bk[0]+1,bk[0]+1+n),cnt[0]=unique(bk[0]+1,bk[0]+1+n)-bk[0]-1;
    	sort(bk[1]+1,bk[1]+1+n),cnt[1]=unique(bk[1]+1,bk[1]+1+n)-bk[1]-1;
    	sort(bk[2]+1,bk[2]+1+n),cnt[2]=unique(bk[2]+1,bk[2]+1+n)-bk[2]-1;
    	sort(bk[3]+1,bk[3]+1+n),cnt[3]=unique(bk[3]+1,bk[3]+1+n)-bk[3]-1;
    	for(int i=1,tmp[4];i<=n;i++)
    	{
    		tmp[0]=lower_bound(bk[0]+1,bk[0]+1+cnt[0],a[i])-bk[0];
    		tmp[1]=lower_bound(bk[1]+1,bk[1]+1+cnt[1],b[i])-bk[1];
    		tmp[2]=lower_bound(bk[2]+1,bk[2]+1+cnt[2],va[i])-bk[2];
    		tmp[3]=lower_bound(bk[3]+1,bk[3]+1+cnt[3],vb[i])-bk[3];
    		pos[0][tmp[0]]=a[i]%P,a[i]=tmp[0];
    		pos[1][tmp[1]]=b[i]%P,b[i]=tmp[1];
    		pos[2][tmp[2]]=va[i]%P,va[i]=tmp[2];
    		pos[3][tmp[3]]=mod(vb[i],P),vb[i]=tmp[3];
    	}
    	dfs2(1,0,1); for(int i=1;i<=n;i++) cout<<ans[i]<<endl;
    }
    
  • 正解 \(100pts\)

    一样的思路但是改成线段树合并,每个点针对其子树开值域线段树,定义 \(val_{l,r},sum_{l,r},cnt_{l,r}\) 分别表示 \(a_{[l,r]}\) 贡献、元素和、元素数量,有 pushup :\(val_{l,r}=ans_{l,mid}+ans_{mid+1,r}+sum_{l,r}\times cnt_{mid+1,r}+sum_{mid+1,r}\times cnt_{l,mid}\)

    拆成四部分分别跑一遍即可。

    懒得打了,甚至比上一个做法好打得多。

T4 团队选拔

抽象玩意,只会 \(16pts\) 部分分,咕了咕了。

posted @ 2024-10-16 10:43  卡布叻_周深  阅读(28)  评论(0编辑  收藏  举报