赛时 rank 20,T1 0,T2 45,T3 20,T4 95
T1粘了两遍(因为OJ卡第一次没有显示出来)CE了,挂了100,T4没卡常挂了5
汤碗了!!!!!!!!!!!!!!!
T1 abc猜想
对于任意整数\(c\)都有
\[\left\lfloor\frac{a}{b}\right\rfloor+c = \left\lfloor\frac{a}{b}+c\right\rfloor = \left\lfloor\frac{a+bc}{b}\right\rfloor \]所以
\[\left\lfloor\frac{a^b}{c}\right\rfloor = kc+ans \]\[ans = \left\lfloor\frac{a^b-kc^2}{c}\right\rfloor = \left\lfloor\frac{a^b\,mod\,c^2 }{c}\right\rfloor \]点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
using ll=long long;using ull=unsigned long long;
#ifdef LOCAL
FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
// FILE *ErrFile=errfile("err.err");
#else
FILE *Infile = stdin,*OutFile = stdout;
//FILE *ErrFile = stderr;
#endif
ll a,b,c;
inline ll power(ll a,ll b,ll mod){
ll res = 1;
while(b){
if(b & 1) res = res * a % mod;
b >>= 1;
a = a*a%mod;
}
return res;
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
cout.tie(nullptr)->sync_with_stdio(false);
cin>>a>>b>>c;
cout<<power(a,b,c*c)/c<<'\n';
}
死亡回放
T2 简单的排列最优化题
\(O(n)\)做法
将排列中的数分为两类,\(\pi_i>i\),\(\pi_i\le i\)
记第一类的总数为\(zcnt\),贡献为\(ztot\);
记第二类的总数为\(fcnt\),贡献为\(ftot\)。
除了放到队首的数,第一类数做出的贡献和减掉\(zcnt\),第二类数做出的贡献和加上\(fcnt\)
当一个数从第一类数变为第二类数时,那么有\(\pi_i-i=0\),预处理每个数变化的时间即可。
第二类数变成第一类数时,只能是是队尾变队首,特判。
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
using ll=long long;using ull=unsigned long long;
#ifdef LOCAL
FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
// FILE *ErrFile=errfile("err.err");
#else
FILE *Infile = stdin,*OutFile = stdout;
//FILE *ErrFile = stderr;
#endif
const int N = 1e7 + 10;
int n,zcnt,fcnt,a[N],Z[N];
ll ztot,ftot;
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
cout.tie(nullptr)->sync_with_stdio(false);
cin>>n;
for(int i = 1;i <= n; ++i) cin>>a[i];
for(int i = 1;i <= n; ++i){
if(a[i] <= i) fcnt++,ftot += i-a[i];
else zcnt++,ztot+=a[i]-i,Z[a[i]-i]++;
}
ll ans = ztot+ftot,id = 0;
for(int i = 1;i < n; ++i){
ztot -= zcnt;
zcnt -= Z[i];
ftot += fcnt;
fcnt += Z[i];
int x = a[n - i + 1];
ftot -= n+1-x,--fcnt;
if(x > 1) Z[x-1+i]++,ztot+= x-1,++zcnt;
else ++fcnt;
if(ans > ftot + ztot) ans = ftot+ztot,id = i;
}
cout<<ans<<' '<<id<<'\n';
}
T3 简单的线性做法题
小清新的分治做法
区间\([l\sim r]\)的绝对众数\(x\)(即出现次数大于\(\frac{len}{2}\)的众数)满足对于任意的\(l\le k\le r\),\(x\)一定为区间\([l\sim k]\)或\((k\sim r]\)的绝对众数。利用这一性质分治,\(O(n)\)从mid出发扫描能够成为众数的数。
枚举众数\(x\),求当前区间中的满足绝对众数为\(x\)的子区间个数。
先从mid开始向左扫描左端点\(b\),记录\(mid-b+1-cnt_x\)不同取值的个数。
再向右扫描右端点\(e\),求满足\(e-b+1-cnt_x > \left\lfloor\frac{e-b+1}{2}\right\rfloor\)的\([b\sim e]\)个数。
时间复杂度\(O(n\log^2n)\)
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
using ll=long long;using ull=unsigned long long;
#ifdef LOCAL
FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
// FILE *ErrFile=errfile("err.err");
#else
FILE *Infile = stdin,*OutFile = stdout;
//FILE *ErrFile = stderr;
#endif
const int N = 5e5 + 10;
int n,a[N],pos[N],num[N],cnt[N*2];
ll ans;
void solve(int l,int r){
if(l == r) {ans++;return;}
int mid = (l+r)>>1;
solve(l,mid);solve(mid+1,r);
for(int i = mid;i >= l;--i){
if(++cnt[a[i]] > (mid - i + 1)/2){
if(!pos[a[i]]) num[pos[a[i]] = ++num[0]] = a[i];
}
}
for(int i = mid+1;i <= r;++i){
if(++cnt[a[i]] > (i - mid)/2){
if(!pos[a[i]]) num[pos[a[i]] = ++num[0]] = a[i];
}
}
for(int i = l;i <= r; ++i) pos[a[i]] = cnt[a[i]] = 0;
for(int i = 1;i <= num[0]; ++i){
int sum = r-l+1,mx = sum,mn = sum;
cnt[sum] = 1;
for(int j = l;j < mid; ++j){
if(a[j] == num[i]) sum++;
else sum--;
mx = max(mx,sum);
mn = min(mn,sum);
cnt[sum]++;
}
if(a[mid] == num[i]) sum++;
else sum--;
for(int j = mn;j <= mx; ++j) cnt[j] += cnt[j - 1];
for(int j = mid+1;j <= r; ++j){
if(a[j] == num[i]) sum++;
else sum--;
ans += cnt[min(mx,sum-1)];
}
for(int i = mn;i <= mx; ++i) cnt[i] = 0;
}
num[0] = 0;
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
cout.tie(nullptr)->sync_with_stdio(false);
cin>>n;int x;cin>>x;
for(int i = 1;i <= n; ++i) cin>>a[i];
solve(1,n);
cout<<ans;
}
T4 简单的线段树题
n很大,分块无法过,线段树维护就可以了,其他的和分块一样,卡卡常数。
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
using ll=long long;using ull=unsigned long long;
#ifdef LOCAL
FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
// FILE *ErrFile=errfile("err.err");
#else
FILE *Infile = stdin,*OutFile = stdout;
//FILE *ErrFile = stderr;
#endif
const int N = 1e6 + 10;
inline void read(ll &x){
x = 0;
char s = getchar();
for(;s<'0'||s >'9';s=getchar());
for(;'0' <= s && s<='9';s=getchar()) x = (x<<1)+(x<<3)+(s^48);
}
ll n,m;ll a[N];
void write(ll x){
if(x > 9) write(x/10);
putchar(x%10+48);
}
struct Segment_Tree{
struct segment_tree{
int l,r,lazy,tot;ll sum;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define sum(x) tree[x].sum
#define lazy(x) tree[x].lazy
#define tot(x) tree[x].tot
}tree[N<<2];
inline void pushup(int k){
sum(k) = sum(k<<1) + sum(k<<1|1);
tot(k) = min(tot(k<<1),tot(k<<1|1));
}
inline void pushdown(int k){
if(lazy(k)){
int ls = k<<1,rs = k<<1|1;
lazy(ls) += lazy(k);
lazy(rs) += lazy(k);
if(tot(ls) >= 6) tot(ls) = 6;
else{
tot(ls) += lazy(k);
sum(ls) = 0;
for(int i = l(ls);i <= r(ls); ++i) sum(ls) += a[i];
}
if(tot(rs) >= 6) tot(rs) = 6;
else{
tot(rs) += lazy(k);
sum(rs) = 0;
for(int i = l(rs);i <= r(rs); ++i) sum(rs) += a[i];
}
lazy(k) = 0;
}
}
void build(int k,int l,int r){
l(k) = l,r(k) = r;
if(l == r)return sum(k) = a[l],void();
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(tot(k) == 6) return;
if(l <= l(k) && r(k) <= r){
if(tot(k) == 6) return;
tot(k)++;lazy(k)++;
sum(k) = 0;
for(int i = l(k);i <= r(k); ++i) sum(k) += (a[i] = sqrt(a[i]));
return;
}
pushdown(k);
int mid = (l(k) + r(k))>>1;
if(l <= mid) update(k<<1,l,r);
if(r > mid) update(k<<1|1,l,r);
pushup(k);
}
ll query(int k,int l,int r){
if(l <= l(k) && r(k) <= r) return sum(k);
pushdown(k);
int mid = (l(k) + r(k))>>1;
ll res = 0;
if(l <= mid) res += query(k<<1,l,r);
if(r > mid) res += query(k<<1|1,l,r);
return res;
}
}T;
signed main(){
read(n);
for(int i = 1;i <= n; ++i) read(a[i]);
T.build(1,1,n);
read(m);
int ttt = 0;
while(m--){
ll op,l,r;
read(op),read(l),read(r);
if(op == 0) T.update(1,l,r);
else write(T.query(1,l,r)),puts("");
// if(op) ttt++;
// if(ttt == 141 && op) cerr<<l<<' '<<r<<'\n';
}
}