【比賽】暑假集訓CSP提高模擬3

萝卜甜了發表於2024-07-26

T1 abc猜想 100Pts

原題 Simple Math 2

簽到題。

對於任意整數 \(c\)

\[\lfloor \frac{a}{b} \rfloor + c = \lfloor \frac{a}{b} + c \rfloor = \lfloor \frac{a+bc}{b} \rfloor \]

設 $ \lfloor \frac{a^b}{c} \rfloor=kc+r(0 \le r < c)$,其中 \(r\) 為答案,那麼 \(r=\lfloor \frac{a^b}{c} \rfloor-kc=\lfloor \frac{a^b-kc^2}{c} \rfloor=\lfloor \frac{a^b \mod c^2}{c} \rfloor\)

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a,b,c;
ll qp(__int128 a,ll b,ll mod){
	__int128 ans=1;
	while(b){
		if(b&1)ans=ans*a%mod;
		b>>=1;
		a=a*a%mod;
	}
	return ans;
}
int main(){
	cin>>a>>b>>c;
	ll d=qp(a,b,c*c);
	ll e=d%c;
	cout<<(d-e)/c;
	return 0;
}

T2 簡單的排列最最佳化題 45 Pts

原題 Mister B and PR Shifts

最終的答案是 \(\sum_{i=1}^n \limits |p_i-i|\),掛絕對值,所以將 \(p_i\) 分為兩類:\(p_i-i>0\)\(p_i-i \le 0\)

然後我們只需要從前往後掃一遍,每次更新扔到隊首元素的貢獻並處理臨界即可。

點選檢視程式碼
#include<bits/stdc++.h>
#define int ll
using namespace std;
typedef long long ll;
const int N=1e6+5;
ll a[N],cnt[N*2];
ll n,bc,bt,sc,st;
main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++){
		if(a[i]>i){
			bc++;
			bt+=a[i]-i;
			cnt[a[i]-i]++;
		}
		else{
			sc++;
			st+=i-a[i];
		}
	}
	ll ans=bt+st,k=0;
	for(int i=1;i<n;i++){
		bt-=bc;
		bc-=cnt[i];
		st+=sc;
		sc+=cnt[i];
		ll x=a[n-i+1];
		st-=n-x+1;
		sc--;
		if(x>1){
			cnt[x+i-1]++;
			bt+=x-1;
			bc++;
		}
		else sc++;
		if(bt+st<ans){
			ans=bt+st;
			k=i;
		}
	}
	cout<<k<<" "<<ans;
	return 0;
}

T3 簡單的線性做法題 25Pts

原題 Yazid 的新生舞會

其實現在還不是很明白,也沒有程式碼,掛一下官方題解吧。

T4 簡單的線段樹題 30Pts

原題 上帝造題的七分鐘 2 / 花神遊歷各國

顯然,開方最多開 \(7\) 次,所以對於每一次詢問我們直接向下推到一個還能開方的區間並開方即可。

用線段樹實現的,然後再校內 oj 上被卡常了,所以又去賀了一版並查集 + 樹狀陣列的。

線段樹
#include<bits/stdc++.h>
#define int ll
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,m,a[N];
struct tree{
	int l,r,maxn,sum;
}t[N<<2];
void pushup(int k){
	t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
	t[k].maxn=max(t[k<<1].maxn,t[k<<1|1].maxn);
}
void build(int k,int l,int r){
	t[k]={l,r,a[l],a[l]};
	if(l==r)return;
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	pushup(k);
}
void update(int k,int l,int r){
	if(t[k].l==t[k].r&&l<=t[k].l&&t[k].r<=r){
		t[k].sum=t[k].maxn=sqrt(t[k].sum);
		return;
	}
	int mid=(t[k].l+t[k].r)>>1;
	if(l<=mid&&t[k<<1].maxn>1)update(k<<1,l,r);
	if(mid<r&&t[k<<1|1].maxn>1)update(k<<1|1,l,r);
	pushup(k);
}
int query(int k,int l,int r){
	if(l<=t[k].l&&t[k].r<=r)return t[k].sum;
	int mid=(t[k].l+t[k].r)>>1;
	int ans=0;
	if(l<=mid)ans+=query(k<<1,l,r);
	if(r>mid)ans+=query(k<<1|1,l,r);
	return ans;
}
main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	build(1,1,n);
	cin>>m;
	for(int i=1,op,l,r;i<=m;i++){
		cin>>op>>l>>r;
		if(l>r)swap(l,r);
		if(op==0)update(1,l,r);
		else cout<<query(1,l,r)<<"\n";
	}
	return 0;
}
樹狀陣列
#include<bits/stdc++.h>
#define int ll
#define lowbit(x) ((x)&(-(x)))
using namespace std;
typedef long long ll;
const int N=1e6+5;
ll n,m,fa[N],a[N],c[N];
int find(int x){
	if(x!=fa[x])fa[x]=find(fa[x]);
	return fa[x];
}
void add(int x,ll val){
	while(x<=n){
		c[x]+=val;
		x+=lowbit(x);
	}
}
ll query(int x){
	ll ans=0;
	while(x){
		ans+=c[x];
		x-=lowbit(x);
	}
	return ans;
}
main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		add(i,a[i]);
		fa[i]=i;
	}
	cin>>m;
	fa[n+1]=n+1;
	for(int i=1,op,l,r;i<=m;i++){
		cin>>op>>l>>r;
		if(op==0){
			for(int i=l;i<=r;){
				int f=find(i);
				if(f!=i)i=f;
				else{
					ll t=sqrt(a[i]);
					add(i,t-a[i]);
					a[i]=t;
					if(a[i]==1){
						fa[i]=i+1;
						i=find(i);
					}
					else i++;
				}
			}
		}
		else{
			cout<<query(r)-query(l-1)<<"\n";
		}
	}
	return 0;
}

相關文章