CF1137E
我们发现只有每一个段首才可能成为答案,套路地考虑到又只有下凸壳上的点才能成为答案。
观察到下凸壳加等差数列还是下凸壳,我们只用每次摆平尾部翘起的部分即可。
对于 \(1\) 操作,只用全部清空,然后新建一个节点就行;对于 \(2\) 操作,如果当前凸包的结尾不是 \(0\) 的话,我们就加一个点进去并维持其凸性;对于 \(3\) 操作,直接加 \(tag\) 然后摆平结尾就是。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define db double
const int maxn=1e6+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m,K,B,top,lasop;
struct node{
int x,y;
node operator-(node t){return (node){x-t.x,y-t.y};}
db operator*(node t){return (db)x*t.y-(db)y*t.x;}
bool operator>=(node t){return y+x*K>=t.y+t.x*K;}
}a[maxn];
signed main(){
n=read(),m=read();
a[top=1]=(node){0,0};
int op,k,b,s;
while(m--){
op=read();
if(op==1){
a[top=1]=(node){0,0};
K=B=0;n+=read();
}else if(op==2){
node p=(node){n,-K*n-B};n+=read();
if(lasop==3){
while(top>=2&&(p-a[top-1])*(a[top]-a[top-1])>0)--top;
a[++top]=p;
}
}else{
B+=read(),K+=read();
while(top>=2&&a[top]>=a[top-1])--top;
}printf("%lld %lld\n\n",a[top].x+1,a[top].y+B+K*a[top].x);
lasop=op;
}
return 0;
}
CF516E
显然模 \(\gcd\) 不同的无关,我们只用考虑 \((n,m)=1\) 的情形。
我们考虑 \(B\) 中最后的时间,同理可以做出 \(G\) 中最后的时间。既然只考虑 \(B\),我们希望所有操作与 \(G\) 无关。
这也很好做到,显然若 \(x\) 有了,那么 \(n\) 时间后 \((x+m)%n\) 也会有,不难发现整个将形成一个大环。
所以我们只用算出环上的编号,然后算每一段最远点的贡献就好。而重编号也是容易的,直接按 \(0,m,2m,3m,\cdots,(n-1)m\) 对 \(n\) 取余这样编号就行。
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m,b,g,gg;long long ans;
vector<int>B[maxn],G[maxn];
#define pb push_back
#define vi vector<int>
#define fi first
#define se second
map<int,int>mp;
inline void exgcd(int &x,int &y,int a,int b){
if(!b){x=1,y=0;return;}
int tx,ty;
exgcd(tx,ty,b,a%b);
x=ty;
y=tx-(a/b)*ty;
}
inline int getinv(int a,int b){
int x,y;exgcd(x,y,a,b);
return (x%b+b)%b;
}
inline void work(vi B,int n,vi G,int m,int i){
if(B.size()==n)return;
int iv=getinv(m,n);long long res=-1;mp.clear();
for(auto x:B)mp[1ll*x*iv%n]=x;
for(auto x:G)if(mp.find(1ll*x*iv%n)==mp.end())
mp[1ll*x*iv%n]=x,res=x;
if(mp.size()==n)return void(ans=max(ans,res*gg+i));
mp[n+mp.begin()->fi]=mp.begin()->se;
for(auto it=mp.begin(),ti=++mp.begin();ti!=mp.end();it++,ti++)
res=max(res,1ll*(ti->fi-it->fi-1)*m+it->se);
ans=max(ans,res*gg+i);
}
int main(){
n=read(),m=read();
gg=__gcd(n,m);n/=gg,m/=gg;
if(gg>200000)return puts("-1")&0;
b=read();while(b--){int x=read();B[x%gg].pb(x/gg);}
g=read();while(g--){int x=read();G[x%gg].pb(x/gg);}
for(int i=0;i<gg;i++){
if(B[i].empty()&&G[i].empty())return puts("-1")&0;
sort(B[i].begin(),B[i].end());
sort(G[i].begin(),G[i].end());
work(B[i],n,G[i],m,i),work(G[i],m,B[i],n,i);
}printf("%lld\n",ans);
return 0;
}//