ABC467
赛时糖完了 G 写了个带修莫队,然后因为没写奇偶化排序 T 飞了……加了个奇偶化排序就过了。
A
显然答案为 \(\left[\dfrac{10^4w}{h^2}\geq25\right]\)。
赛时代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int w,h;
cin>>h>>w;
if(10000.0*w/h/h>=25){
cout<<"Yes\n";
}else{
cout<<"No\n";
}
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}
B
没找钱的就记录答案,答案为:
赛时代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=100,V=100;
int n,a[N+1],b[N+1];
string s[N+1];
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
int ans=0;
for(int i=1;i<=n;i++){
cin>>a[i]>>b[i]>>s[i];
switch(s[i][0]){
case'k':
ans+=b[i]-a[i];
break;
case 't':
break;
}
}
cout<<ans<<'\n';
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}
C
没想 \(m=2\) 的单独做法, 准备复制 E 的代码,先写了 D。
D
容易发现,圆心在 \(PQ,RS\) 的垂直平分线的交点上:
无解的情况是这两条直线无交。即直线不重合且 \(\dfrac{y_p-y_q}{x_p-x_q}=\dfrac{y_r-y_s}{x_r-x_s}\)。
直线重合的时候是有圆心的,再判一下直线重合即可。
赛时代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
struct node{
int x,y;
}p,q,r,s;
struct frac{
int a,b;
};
frac k(node a,node b){
return {a.y-b.y,a.x-b.x};
}
bool operator ==(frac x,frac y){
return 1ll*x.a*y.b==1ll*y.a*x.b;
}
bool check(frac k1,frac k2){
ll dx=q.x-p.x;
ll dy=q.y-p.y;
ll mx=p.x+q.x-r.x-s.x;
ll my=p.y+q.y-r.y-s.y;
return !(k1==k2)||(mx*dx+my*dy)==0;
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T;
cin>>T;
while(T--){
cin>>p.x>>p.y>>q.x>>q.y>>r.x>>r.y>>s.x>>s.y;
frac k1=k(p,q);
frac k2=k(r,s);
if(!check(k1,k2)){
cout<<"No\n";
}else{
cout<<"Yes\n";
}
}
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}
E
设 \(a_i\) 操作了 \(x_i\) 次,则 \(a_i\) 会变为 \(a_i+x_i\)。
那么原要求等价于 \(a_i+a_{i+1}+x_i+x_{i+1}\equiv b_i\pmod m\),即 \(x_i+x_{i+1}\equiv b_i-a_i-a_{i+1}\pmod m\)。令 \(c_i=b_i-a_i-a_{i+1}\)。
\(x_1\) 已知,之后就可以直接求出来 \(x_1,x_2,\cdots,x_n\)。
之后是一个分段函数,求最小值。
赛时代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#include<map>
using namespace std;
#define int long long
constexpr const int N=2e5,M=1e9;
int n,m,a[N+1],b[N+1],c[N+1],p[N+1];
main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<n;i++){
cin>>b[i];
}
for(int i=1;i<n;i++){
c[i]=(b[i]-a[i]-a[i+1])%m;
if(c[i]<0){
c[i]+=m;
}
}
p[1]=0;
for(int i=2;i<=n;i++){
p[i]=(c[i-1]-p[i-1])%m;
if(p[i]<0){
p[i]+=m;
}
}
int pre=0,k=0;
for(int i=1;i<=n;i++){
a[i]=p[i];
pre+=a[i];
if(i&1){
k++;
}else{
k--;
}
}
map<int,int>d;
for(int i=1;i<=n;i++){
if(i&1){
if(a[i]>0){
d[m-a[i]]-=m;
}
}else{
if(a[i]<m-1){
d[a[i]+1]+=m;
}
}
}
vector<int>v{m-1};
for(auto [i,j]:d){
v.push_back(i);
}
sort(v.begin(),v.end());
v.resize(unique(v.begin(),v.end())-v.begin());
int ans=pre,pl=pre;
for(int i=0;i<v.size();i++){
int x=v[i];
if(i==0){
pl+=k*x;
}else{
pl+=k*(x-v[i-1]);
}
pl+=d[x];
ans=min(ans,pl);
}
cout<<ans<<'\n';
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}
F
贪心,把 \((a_i,b_i)\) 按照 \(b_i\) 从大到小排序,答案即:
但是 \(a_i,b_i\) 会做单点修改,考虑用数据结构维护。
用平衡树以 \(b_i\) 为关键字维护每个点的 \((a_i,b_i)\),然后每个节点维护一下左子树里的 \(\sum a_j\) 即可。
赛时代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#include<random>
using namespace std;
typedef long long ll;
constexpr const int N=1e5,Q=1e5;
constexpr const ll inf=0x3f3f3f3f3f3f3f3f;
mt19937 Rand(time(0));
int n,a[N+1],b[N+1];
int root;
struct FHQTreap{
int size;
struct node{
pair<int,int>value;
int size,rand;
int lChild,rChild;
ll ans,sumA;
}t[N+Q+1];
FHQTreap(){
size=root=0;
t[0].ans=inf;
t[0].sumA=0;
}
int create(pair<int,int> x){
t[++size]={x,1,Rand(),0,0,x.first+x.second,x.second};
return size;
}
void up(int p){
t[p].size=t[t[p].lChild].size+t[t[p].rChild].size+1;
t[p].ans=min({t[t[p].lChild].ans , t[t[p].lChild].sumA+t[p].value.first+t[p].value.second , t[t[p].lChild].sumA+t[p].value.second+t[t[p].rChild].ans});
t[p].sumA=t[t[p].lChild].sumA+t[p].value.second+t[t[p].rChild].sumA;
}
void split(int p,pair<int,int> x,int &l,int &r,bool flag=true){
if(!p){
l=r=0;
return;
}
if(t[p].value<x||t[p].value==x&&flag){
l=p;
split(t[p].rChild,x,t[p].rChild,r,flag);
}else{
r=p;
split(t[p].lChild,x,l,t[r].lChild,flag);
}
up(p);
}
int merge(int l,int r){
if(!l||!r){
return l|r;
}
if(t[l].rand<t[r].rand){
t[l].rChild=merge(t[l].rChild,r);
up(l);
return l;
}else{
t[r].lChild=merge(l,t[r].lChild);
up(r);
return r;
}
}
void insert(pair<int,int> x){
int l,r,p;
split(root,x,l,r);
root=merge(merge(l,create(x)),r);
}
void erase(pair<int,int> x){
int l,r,p;
split(root,x,l,r);
split(l,x,l,p,false);
p=merge(t[p].lChild,t[p].rChild);
root=merge(merge(l,p),r);
}
ll query(){
return -t[root].ans;
}
}t;
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int q;
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
for(int i=1;i<=n;i++){
t.insert({-b[i],-a[i]});
}
while(q--){
int op,i,x;
cin>>op>>i>>x;
t.erase({-b[i],-a[i]});
switch(op){
case 1:
a[i]=x;
break;
case 2:
b[i]=x;
break;
}
t.insert({-b[i],-a[i]});
cout<<t.query()<<'\n';
}
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}
G
据说是主席树板子题,然而我并不会。
观察数据范围 \(10^5\),可以思考一个根号做法,考虑带修莫队。
但是这样离散化之后还是会有 \(M\leq3\times10^5\) 个数,暴力统计答案会 TLE。考虑分块,然后可以做到 \(\mathcal O\left(\sqrt M\right)\) 查询。
时间复杂度就带修莫队拼上 \(q\) 次查询,\(n,q\) 同阶,即 \(\mathcal O\left(n^{\frac53}+n^{\frac32}\right)\)。
然后几乎就是板子题,赛后写个奇偶化排序就过了,赛时没写奇偶化排序 T 飞了。
赛后代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
constexpr const int N=2e5,Q=2e5,V=5e5;
int n,m,sizeQ,sizeOp,init[N+1],a[N+1],real[N+1];
ll value[V+1];
int M,Bv,bc;
int bid[V+1],bl[N+1],br[N+1],cv[V+1],cb[N+1];
ll sv[V+1],sb[N+1];
ll tot;
void build(){
Bv=sqrt(M)+1;
bc=(M+Bv-1)/Bv;
for(int b=1;b<=bc;b++){
bl[b]=(b-1)*Bv+1;
br[b]=min(b*Bv,M);
for(int v=bl[b];v<=br[b];v++)
bid[v]=b;
}
}
struct question{
int l,r;
ll k;
int t,id;
}q[Q+1];
struct operation{
int pos,color,backup;
}op[Q+1];
int ans[Q+1];
int B,size,pos[N+1],edgeL[N+1],edgeR[N+1];
void pre(){
B=pow(n,2/3.0);
for(int i=1;edgeR[i-1]+1<=n;i++){
edgeL[i]=edgeR[i-1]+1;
edgeR[i]=min(edgeL[i]+B-1,n);
for(int j=edgeL[i];j<=edgeR[i];j++)
pos[j]=i;
}
sort(q+1,q+sizeQ+1,[](question a,question b){
if(pos[a.l]!=pos[b.l]){
return pos[a.l]<pos[b.l];
}else if(pos[a.r]!=pos[b.r]){
if(pos[a.l]&1){
return pos[a.r]<pos[b.r];
}else{
return pos[a.r]>pos[b.r];
}
}else{
if(pos[a.r]&1){
return a.t<b.t;
}else{
return a.t>b.t;
}
}
});
}
void addLeft(int &l,int &r,int &t){
l--;
int v=a[l];
cv[v]++;
sv[v]+=value[v];
tot+=value[v];
int b=bid[v];
cb[b]++;
sb[b]+=value[v];
}
void addRight(int &l,int &r,int &t){
r++;
int v=a[r];
cv[v]++;
sv[v]+=value[v];
tot+=value[v];
int b=bid[v];
cb[b]++;
sb[b]+=value[v];
}
void delLeft(int &l,int &r,int &t){
int v=a[l];
cv[v]--;
sv[v]-=value[v];
tot-=value[v];
int b=bid[v];
cb[b]--;
sb[b]-=value[v];
l++;
}
void delRight(int &l,int &r,int &t){
int v=a[r];
cv[v]--;
sv[v]-=value[v];
tot-=value[v];
int b=bid[v];
cb[b]--;
sb[b]-=value[v];
r--;
}
void moveUp(int &l,int &r,int &t){
t++;
int p=op[t].pos;
if(l<=p&&p<=r){
int old=a[p];
cv[old]--;
sv[old]-=value[old];
tot-=value[old];
int b=bid[old];
cb[b]--;
sb[b]-=value[old];
}
a[p]=op[t].color;
if(l<=p&&p<=r){
int nw=a[p];
cv[nw]++;
sv[nw]+=value[nw];
tot+=value[nw];
int b=bid[nw];
cb[b]++;
sb[b]+=value[nw];
}
}
void moveDown(int &l,int &r,int &t){
int p=op[t].pos;
if(l<=p&&p<=r){
int nw=a[p];
cv[nw]--;
sv[nw]-=value[nw];
tot-=value[nw];
int b=bid[nw];
cb[b]--;
sb[b]-=value[nw];
}
a[p]=op[t].backup;
if(l<=p&&p<=r){
int old=a[p];
cv[old]++;
sv[old]+=value[old];
tot+=value[old];
int b=bid[old];
cb[b]++;
sb[b]+=value[old];
}
t--;
}
int calc(ll k){
if(tot<k)return -1;
ll rem=k;
int ans=0;
for(int b=bc;b>=1;b--){
if(rem<=0)break;
if(sb[b]==0)continue;
if(sb[b]>=rem){
for(int v=br[b];v>=bl[b];v--){
if(rem<=0)break;
if(cv[v]==0)continue;
ll s=sv[v];
if(s>=rem){
ans+=(rem+value[v]-1)/value[v];
rem=0;
break;
}else{
rem-=s;
ans+=cv[v];
}
}
break;
}else{
rem-=sb[b];
ans+=cb[b];
}
}
return ans;
}
void discist(){
static int tmp[V+1];
M=0;
for(int i=1;i<=n;i++){
tmp[++M]=init[i];
}
for(int i=1;i<=sizeOp;i++){
tmp[++M]=op[i].color;
tmp[++M]=op[i].backup;
}
sort(tmp+1,tmp+M+1);
M=unique(tmp+1,tmp+M+1)-tmp-1;
for(int i=1;i<=M;i++){
value[i]=tmp[i];
}
for(int i=1;i<=n;i++){
a[i]=lower_bound(tmp+1,tmp+M+1,init[i])-tmp;
}
for(int i=1;i<=sizeOp;i++){
op[i].color=lower_bound(tmp+1,tmp+M+1,op[i].color)-tmp;
op[i].backup=lower_bound(tmp+1,tmp+M+1,op[i].backup)-tmp;
}
}
main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>init[i];
real[i]=init[i];
}
sizeQ=sizeOp=0;
for(int i=1;i<=m;i++){
int c,x,l,r;ll k;
cin>>c>>x>>l>>r>>k;
op[++sizeOp]={c,x,real[c]};
real[c]=x;
sizeQ++;
q[sizeQ]={l,r,k,sizeOp,sizeQ};
}
discist();
build();
pre();
int l=1,r=0,t=0;
tot=0;
for(int i=1;i<=sizeQ;i++){
while(l>q[i].l){
addLeft(l,r,t);
}
while(r<q[i].r){
addRight(l,r,t);
}
while(l<q[i].l){
delLeft(l,r,t);
}
while(r>q[i].r){
delRight(l,r,t);
}
while(t<q[i].t){
moveUp(l,r,t);
}
while(t>q[i].t){
moveDown(l,r,t);
}
ans[q[i].id]=calc(q[i].k);
}
for(int i=1;i<=sizeQ;i++){
cout<<ans[i]<<'\n';
}
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号