NOIP2024 前集訓:MX 煉石計劃 NOIP 模擬賽 20

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

前言

music
《望》

紅色風箏 俯瞰著地圖
飄太遠 在哪兒 著陸
遠行的人 是望遠鏡裡的模糊
借背影放大孤獨
你我習慣 像常旅客來了又去
寄天空的信 未能 按時 回覆
再等一等就返航 如初
我們總會 繞啊繞 繞啊繞
繞幾千里路 也望向歸途
乘著風想念吹拂 遊夜空漂浮
抓一顆流星做禮物 願你幸福
手中線 繞啊繞 繞啊繞
繞幾千日夜 也望向歸途
燕歸巢遷徙之路 參與者無數
待到煙火照夜白時準備慶祝 心有所住
兒時總愛 掰著手默數
好希望 快些到 日出
長大的人 被挾裹著說不得不
借不到藉口停駐
你我習慣 像常旅客來了又去
寄天空的信 未能 按時 回覆
再等一等就返航 如初
我們總會 繞啊繞 繞啊繞
繞幾千里路 也望向歸途
乘著風想念吹拂 遊夜空漂浮
抓一顆流星做禮物 願你幸福
手中線 繞啊繞 繞啊繞
繞幾千日夜 也望向歸途
燕歸巢遷徙之路 參與者無數
待到煙火照夜白時準備慶祝 心有所住
我們總會 繞啊繞 繞啊繞
繞幾千里路 也望向歸途
乘著風思念吹拂 遊夜空漂浮
抓一顆流星祝福 你要幸福
手中線 繞啊繞 繞啊繞
繞幾千日夜 也望向歸途
燕歸巢遷徙之路 參與者無數
待到煙火照夜白時準備慶祝 心有所住

今天不知道為啥去打 MX 了,bug 不少啊,包括但不限於賽時能透過自己主頁看自己題過沒過,賽時可以進入“補題”的比賽交從而直接成 IOI 賽制,檔案還有點問題?

0+100+12+0,T1 讀假題:\(\ge×,>√\),喜提爆零,但是本來就不會正解,我去我表都打出來了不知道二分??!?!!?

不打 T4 是錯誤的,亂搞能得的分挺多的。

T2 是籤,線段樹直接跑就行了,行為是值域線段樹所以從 \(0\) 開始,結果查詢的時候忘了還是從 \(1\) 開始的,唐了好長時間,然後因為有 \(0\),所以不能用查理線段樹。

下午到機房不知道為啥困得快死了,在機房睡了不知道多長時間。

T1 鄰間的骰子之舞

\(x\) 表示複製,\(y\) 表示貼上,打表或者基本不等式證一下,則最優解一定是形如 \(x~k\cdot y~x~k\cdot y…x~(k-1)\cdot y~x~(k-1)\cdot y…\) 的形式,發現 \(x\) 的個數 \(\le\log_2(n)\),可以直接列舉,\(k\) 則可以直接二分,再列舉 \(k\)\(k-1\) 的斷點,複雜度 \(O(\log^3)\),發現每次都列舉 \(k\) 是唐氏,改成 \(O(\log^2)\) 的。

點選檢視程式碼
#include<bits/stdc++.h>
#define ll long long
#define ull __int128
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e6+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...);}
ll n; int m; ull x,y,ans=1e27;
inline bool check(int x,ll y)
{ull res=1; while(x--) {res*=y; if(res>n) return 1;} return 0;}
inline ull qpow(ull a,int b)
{ull res=1; for(;b;a*=a,b>>=1) (b&1)&&(res*=a); return res;}
signed main()
{
	freopen("dice.in","r",stdin),freopen("dice.out","w",stdout);
	read(n,x,y),m=log2(n)+1;
	for(int i=1;i<=m;i++)
	{
		ll l=0,r=n,mid,res;
		while(l<=r) check(i,(mid=l+r>>1)+1)?r=(res=mid)-1:l=mid+1;
		ull sum=qpow(res,i); for(int j=1;j<=i;j++)
		{
			sum/=res,sum*=(res+1);
			sum>n&&(ans=min(ans,(x+(res-1)*y)*i+y*j));
		}
	}
	write(ans);
}

T2 星海浮沉錄

對於一個值 \(pre_i\),表示 \(i\) 距離上一個 \(a_i\) 出現位置的距離,那麼若存在 \(pre_i>x\)\(a_i\) 就可能成為 \(mex\),那麼對於每一個權值維護其最大的 \(pre\),最後線上段樹上跑二分找到最小的 \(a_i\) 滿足 \(pre_i>a_i\) 即可。

點選檢視程式碼
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
#define mid (l+r>>1)
#define ls (p<<1)
#define rs (p<<1|1)
#define pb push_back
using namespace std;
const int N=1e6+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,a[N],rk[N],pre[N],now[N]; vector<int>e[N],pos[N];
struct private_tree
{
	vector<int>mx;
	inline void build(int p,int l,int r,int x)
	{
		if(l==r) return mx[p]=pre[e[x][l-1]],void();
		build(ls,l,mid,x),build(rs,mid+1,r,x),mx[p]=max(mx[ls],mx[rs]);
	}
	inline void init(int x,int siz) {mx.resize((siz+5)<<2),build(1,1,siz,x);}
	inline void change(int p,int l,int r,int x,int d)
	{
		if(l==r) return mx[p]=d,void();
		x<=mid?change(ls,l,mid,x,d):change(rs,mid+1,r,x,d);
		mx[p]=max(mx[ls],mx[rs]);
	}
}t[N];
struct total_tree
{
	int mx[N<<2];
	inline void build(int p,int l,int r)
	{
		if(l==r) return mx[p]=t[l].mx[1],void();
		build(ls,l,mid),build(rs,mid+1,r),mx[p]=max(mx[ls],mx[rs]);
	}
	inline void change(int p,int l,int r,int x,int d)
	{
		if(l==r) return mx[p]=d,void();
		x<=mid?change(ls,l,mid,x,d):change(rs,mid+1,r,x,d);
		mx[p]=max(mx[ls],mx[rs]);
	}
	inline int ask(int p,int l,int r,int x)
	{
		if(l==r) return l;
		if(mx[ls]>=x) return ask(ls,l,mid,x);
		if(mx[rs]>=x) return ask(rs,mid+1,r,x);
		return n+1;
	}
}T;
signed main()
{
	freopen("star.in","r",stdin),freopen("star.out","w",stdout);
	read(n,m); for(int i=1;i<=n;i++)
		read(a[i]),pre[i]=i-now[a[i]]-1,e[a[i]].pb(now[a[i]]=i);
	for(int i=0;i<=n;i++)
		pre[n+i+1]=n-now[i],e[i].pb(n+i+1),t[i].init(i,e[i].size());
	T.build(1,0,n); for(int i=0;i<=n;i++)
	{
		pos[i].pb(0); for(int j=0;j<e[i].size();j++)
			rk[e[i][j]]=j+1,pos[i].pb(e[i][j]);
	}
	for(int op,x;m;m--)
	{
		read(op,x); if(op==1)
		{
			if(a[x]==a[x+1]) continue;
			t[a[x]].change(1,1,e[a[x]].size(),rk[x],++pre[x]);
			t[a[x]].change(1,1,e[a[x]].size(),rk[x]+1,--pre[pos[a[x]][rk[x]+1]]);
			T.change(1,0,n,a[x],t[a[x]].mx[1]);
			t[a[x+1]].change(1,1,e[a[x+1]].size(),rk[x+1],--pre[x+1]);
			t[a[x+1]].change(1,1,e[a[x+1]].size(),rk[x+1]+1,++pre[pos[a[x+1]][rk[x+1]+1]]);
			T.change(1,0,n,a[x+1],t[a[x+1]].mx[1]);
			swap(pos[a[x]][rk[x]],pos[a[x+1]][rk[x+1]]);
			swap(a[x],a[x+1]),swap(rk[x],rk[x+1]),swap(pre[x],pre[x+1]);
		}
		else write(T.ask(1,0,n,x)),puts("");
	}
}

T3 勾指起誓

高階多項式題,再見。

T4 第八交響曲

雙調排序。

對於一個單峰序列,設 \(n=2^k\),對於 \(i\in [1,2^{k-1}]\) 執行一次 \((i,i+2^{k-1})\) 操作,則序列會變成一個滿足 \(\forall i\in[1,2^{k-1}],j\in [2^{k-1}+1,2^k],a_i<a_j\) 的兩個單峰序列。

那麼對於一個亂序的序列,假設可以將他變成兩個有序序列,考慮合併兩個有序序列,發現只有把有區間的所有數翻轉就和上面一樣了,於是就可以遞迴求解了,複雜度 \(O(\frac{k(k+1)}{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
using namespace std;
const int N=110;
int n,ans,pos1[N],pos2[N][N]; vector<pair<int,int> >e[N];
inline void solve2(int l,int r,int dep,int top)
{
	if(l==r) return ; int mid=l+r>>1;
	if(!pos2[top][dep]) pos2[top][dep]=++ans;
	for(int i=l,j=mid+1;j<=r;i++,j++) e[pos2[top][dep]].pb(mkp(i,j));
	solve2(l,mid,dep+1,top),solve2(mid+1,r,dep+1,top);
}
inline void solve1(int l,int r,int dep)
{
	if(l==r) return ; int mid=l+r>>1;
	solve1(l,mid,dep+1),solve1(mid+1,r,dep+1);
	if(!pos1[dep]) pos1[dep]=++ans;
	for(int i=l,j=r;j>mid;i++,j--) e[pos1[dep]].pb(mkp(i,j));
	solve2(l,mid,dep+1,dep),solve2(mid+1,r,dep+1,dep);
}
signed main()
{
	freopen("symphony.in","r",stdin),freopen("symphony.out","w",stdout); 
	scanf("%d",&n); int tmp=n; n=powl(2,ceil(log2(n)));
	solve1(1,n,1),printf("%d\n",ans);
	for(int i=1;i<=ans;i++,puts("")) for(auto j:e[i])
		if(j.fi<=tmp&&j.se<=tmp) printf("CMPSWP R%d R%d ",j.fi,j.se);
}

相關文章