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;
}