NOIP2024 前集訓:NOIP2024加賽 8

卡布叻_周深發表於2024-11-27

前言

music
《鈴芽之旅》

du du du du du du du du du du du du du du du du

du du du du du du du du du du du du du du du du

du du du du du du du du du du du du du du du du

du du du du du du du du du du du du du du du du

於 你的生命之中

紅與藍的線纏繞交錯

在 心間劃上最後一筆

勾勒出你的脈絡

那 隨風飄蕩的聲音 從不曾被吹散片刻

是 藏在心中的話 想對你說卻還沒能說

人生啊 短暫如花

微風啊 拂過臉頰

星光啊 照誰的家

我們是 宇宙一剎

別再問 別再問 這樣的我 為什麼哭著

眼淚替我訴說

意義是你 意義是我

意義總是 難以追尋的

是我們相遇過 誰奮力吶喊著

卻吼不破命運的殼

只能是你 只能由你

觸碰雙手輕輕喚醒我

沉睡千年的心搏

意義是你 意義是我

意義是否 最終跨越呢

相隔時空的你我

是愚昧又如何 是醜惡又如何 是望著前方正確的因果

是想與你攜手走過

如今我已想不起

曾經珍惜的回憶

卻似有萬千言語

深深埋葬在我心底

或許就這樣吧 或許就這樣了

還有什麼遺憾的 我已交付所有的自己

或許就這樣吧 或許就這樣了

多麼想讓你聽見

這顆破碎又頑強的心

只想靠近你

別再問 別再問 這樣的我 為什麼哭著

眼淚替我訴說

意義是你 意義是我 意義總是 難以追尋的

是我們相遇過 誰奮力吶喊著

卻吼不破命運的殼

只能是你只能由你

觸碰雙手輕輕喚醒我

沉睡千年的心搏

意義是你 意義是我

意義是否 最終跨越呢

相隔時空的你我

是愚昧又如何 是醜惡又如何

是望著前方 正確的因果

是想與你攜手走過

今天中午打電話我媽告訴我遇到詐騙了,詐騙的不知道從哪兒弄來我的簡訊給我媽發訊息交錢,不過我這輩子沒用過簡訊,再說我有事兒肯定打電話,最主要的是我從來沒朝我媽要過錢,所以我媽一眼看出來是詐騙了。

但是挺離譜的詐騙的為啥會搞到我手機號還能知道我媽是誰還能知道我是學 OI 的?

T1 賽時不知道貪心是對的,奔著隨機資料去的結果 A 了;T2 忘初始化保齡了;T4 沒開 long long(開了,但是不知道啥時候給刪了)掛了 35。

明天不想打了嗚嗚嗚,還沒打板子呢,但是如果明天不打今天可能就是最後一場了。

T1 flandre

貪心的發現一定是優先選大的,然後肯定是把小的排在前面。

點選檢視程式碼
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e6+10,mx=1e6;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char a=getchar_unlocked();
	for(;!isdigit(a);a=getchar_unlocked()) if(a=='-') z=0;
	for(;isdigit(a);a=getchar_unlocked()) x=(x<<1)+(x<<3)+(a^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,tot,top,a[N],pos[N],sta[N]; ll k,ans,sum; vector<int>e[N<<1];
signed main()
{
	freopen("flandre.in","r",stdin),freopen("flandre.out","w",stdout);
	read(n,k);
	for(int i=1;i<=n;i++) read(a[i]),e[a[i]+mx].push_back(i);
	for(int i=mx;~i;i--) if(!e[i+mx].empty())
	{
		ans+=1ll*e[i+mx].size()*(i+k*m),m+=e[i+mx].size();
		for(int j:e[i+mx]) pos[++tot]=j;
	}
	sum=ans; for(int i=-1,tmp=0;i>=-mx;i--,tmp=0) if(!e[i+mx].empty())
	{
		for(int j=1;j<=e[i+mx].size();j++) if(sum+j*(k*m+i)>ans)
		{
			for(int h=1;h<=top;h++) pos[++tot]=sta[h];
			for(int h=tmp;h<j;h++) pos[++tot]=e[i+mx][h];
			ans=sum+j*(k*m+i),tmp=j,top=0;
		}
		for(int j=tmp;j<e[i+mx].size();j++) sta[++top]=e[i+mx][j];
		sum+=e[i+mx].size()*(i+k*m),m+=e[i+mx].size();
	}
	write(ans,tot),puts(""),reverse(pos+1,pos+1+tot);
	for(int i=1;i<=tot;i++) write(pos[i]),putchar_unlocked(' ');
}

T2 meirin

往資料結構上想了,實際上是道數學題。

考慮把式子拆開,這是簡單的,有很多種方式可以把他拆成單詞 \(O(n)\) 的,但是需要把他拆成修改 \(O(1)\sim O(\log)\) 的。

發現 \(a_i\) 始終不變,考慮把 \(a_i\) 當成係數拎出來,轉換後有:

\[\sum_{l=1}^r\sum_{r=l}^n(\sum_{i=l}^ra_i)\times (\sum_{i=l}^rb_i)=\sum_{i=1}^n((i\times \sum_{j=i}^nsum_j)-((n-i+1)\times \sum_{j=1}^isum_{j-1}))b_i \]

\(sum_i\) 表示字首和,發現轉換為了 \(b_i\) 係數的形式,於是就可以直接算貢獻了。

點選檢視程式碼
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=5e5+10,P=1e9+7;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char a=getchar_unlocked();
	for(;!isdigit(a);a=getchar_unlocked()) if(a=='-') z=0;
	for(;isdigit(a);a=getchar_unlocked()) x=(x<<1)+(x<<3)+(a^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,ans,a[N],b[N];
inline int mod(int x,int y) {return (x+=y)>=P?x-P:x;}
signed main()
{
	freopen("meirin.in","r",stdin),freopen("meirin.out","w",stdout);
	read(n,m);
	for(int i=1,x;i<=n;i++) read(x),a[i]=mod(a[i-1],mod(x,P));
	for(int i=1;i<=n;i++) a[i]=mod(a[i-1],a[i]);
	for(int i=1,x;i<=n;i++)
	{
		b[i]=mod(1ll*mod(a[n],P-a[i-1])*i%P,P-1ll*a[i-1]*(n-i+1)%P);
		read(x),ans=mod(ans,1ll*b[i]*mod(x,P)%P),b[i]=mod(b[i-1],b[i]);
	}
	for(int l,r,x;m;m--)
	{
		read(l,r,x);
		write(ans=mod(ans,1ll*mod(b[r],P-b[l-1])*mod(x,P)%P)),puts("");
	}
}

T3 sakuya

考慮統計邊 \((x,y)\) 出現的次數,斷開這條邊樹會分成兩部分,這條邊被計算當且僅當相鄰的兩點分別在兩部分中,那麼這部分可以用樹形 DP 做了。

考慮兩點相鄰的機率,用捆綁法求出兩點相鄰的機率為 \(\dfrac{2(m-1)!}{m!}=\dfrac{2}{m}\)

加貢獻的時候直接根據求出的 DP 加就可以了。

點選檢視程式碼
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=5e5+10,P=998244353;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char a=getchar_unlocked();
	for(;!isdigit(a);a=getchar_unlocked()) if(a=='-') z=0;
	for(;isdigit(a);a=getchar_unlocked()) x=(x<<1)+(x<<3)+(a^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,tot,ans,f[N],sz[N]; ll inv; int head[N],nxt[N<<1],to[N<<1],w[N<<1];
inline int mod(int x,int y) {return (x+=y)>=P?x-P:x;}
inline int qpow(ll a,int b)
{ll res=1; for(;b;(a*=a)%=P,b>>=1) (b&1)&&((res*=a)%=P); return res;}
inline void add(int x,int y,int z)
{nxt[++tot]=head[x],to[tot]=y,w[tot]=z,head[x]=tot;}
inline void dfs1(int x,int t)
{for(int i=head[x],y;y=to[i];i=nxt[i]) if(y!=t) dfs1(y,x),sz[x]+=sz[y];}
inline void dfs2(int x,int t)
{
	f[t]=mod(f[t],1ll*sz[x]*(m-sz[x])%P);
	for(int i=head[x],y,tmp;y=to[i];i=nxt[i]) if(y!=t)
	{
		f[y]=mod(f[y],tmp=1ll*sz[y]*(m-sz[y])%P);
		ans=mod(ans,1ll*tmp*w[i]%P),dfs2(y,x);
	}
}
signed main()
{
	freopen("sakuya.in","r",stdin),freopen("sakuya.out","w",stdout);
	read(n,m),inv=qpow(m,P-2)*2%P;
	for(int i=1,x,y,z;i<n;i++) read(x,y,z),add(x,y,z),add(y,x,z);
	for(int i=1,x;i<=m;i++) read(x),sz[x]=1; dfs1(1,0),dfs2(1,0),read(m);
	for(int x,k;m;m--,write(ans*inv%P),puts(""))
		read(x,k),ans=mod(ans,1ll*f[x]*k%P);
}

T4 紅樓 ~ Eastern Dream

已經把根號分治寫臉上了,問題在於怎麼分別處理。

對於 \(x\le \sqrt n\) 的因為這種點最多隻有 \(\sqrt n\) 個,所以直接算即可。

對於 \(x>\sqrt n\) 的,直接線段樹會多個 \(\log\) 過不去,考慮序列分塊加差分,從而做到每個塊 \(O(1)\) 更新 \(O(\sqrt n)\) 查詢,維護差分的方式和樹狀陣列維護區間改區間查相同。

點選檢視程式碼
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=2e5+10,M=300,L=1000;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char a=getchar_unlocked();
	for(;!isdigit(a);a=getchar_unlocked()) if(a=='-') z=0;
	for(;isdigit(a);a=getchar_unlocked()) x=(x<<1)+(x<<3)+(a^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,len,vl[N],vr[N],pos[N]; ll ans,a[N],b[N],c[N],s1[L],s2[L],d[M][M];
inline void add(int l,int r,int k)
{
	c[l]+=k,s1[pos[l]]+=k,s2[pos[l]]+=1ll*(vr[pos[l]]-l+1)*k;
	c[++r]-=k,s1[pos[r]]-=k,s2[pos[r]]-=1ll*(vr[pos[r]]-r+1)*k;
}
inline ll ask1(int x,int y) {return ~y?(y/x)*b[x]+d[x][y%x]:0;}
inline ll ask2(int l,int r)
{
	ll res=0; int x=pos[l],y=pos[r];
	for(int i=1;i<x;i++) res+=s1[i]*(r-l+1);
	for(int i=vl[x];i<l;i++) res+=c[i]*(r-l+1);
	if(x==y) {for(int i=l;i<=r;i++) res+=c[i]*(r-i+1); return res;}
	for(int i=l;i<=vr[x];i++) res+=c[i]*(r-i+1);
	for(int i=x+1;i<y;i++) res+=s1[i]*(r-vr[i])+s2[i];
	for(int i=vl[y];i<=r;i++) res+=c[i]*(r-i+1); return res;
}
signed main()
{
	freopen("scarlet.in","r",stdin),freopen("scarlet.out","w",stdout);
	read(n,m),len=max(1,(int)sqrt(n)/2);
	for(int i=1;i<=n;i++) read(a[i]),a[i]+=a[i-1],pos[i]=(i-1)/len+1;
	for(int i=1;i<=pos[n];i++) vl[i]=vr[i-1]+1,vr[i]=min(n,i*len);
	for(int op,x,y,k;m;m--)
	{
		read(op,x,y); if(op&1)
		{
			read(k),y=min(x-1,y); if(x<=len)
			{
				b[x]+=1ll*k*(y+1);
				for(int i=0;i<=y;i++) d[x][i]+=1ll*(i+1)*k;
				for(int i=y+1;i<x;i++) d[x][i]+=1ll*(y+1)*k;
			}
			else for(int i=1;i<=n;i+=x) add(i,min(n,i+y),k); continue;
		}
		for(int i=1;i<=len;i++) ans+=ask1(i,y-1)-ask1(i,x-2);
		write(ans+a[y]-a[x-1]+ask2(x,y)),puts(""),ans=0;
	}
}

相關文章