省选模拟3.13
A. 跑步
只想到了每次修改的小方格内的左端点是单调的
一开始以为右端点和左端点一样是不断向里走的,然后发现错了
就没想到,右端点也是单调向右走的
然后用树状数组维护每个位置的 \(f\) 值就行了
然后再判断每次修改的左右端点是否移动就好了
Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define lowbit(x) x&-x
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,ans;
int a[2010][2010],f[2010][2010];
char str[10];
struct bit{
int a[2010];
inline void upd(int x,int k){
for(;x<=n;x+=lowbit(x)) a[x]+=k;
}
inline int query(int x){
if(!x) return 0;int res=0;
for(;x;x-=lowbit(x)) res+=a[x];
return res;
}
}BIT[2010];
inline void upd(int x,int y,int k){
int l=y,r=y+1;a[x][y]+=k;r=min(r,n);
for(int i=x;i<=n;i++){
while(l<=n&&((max(BIT[i].query(l-1) ,BIT[i-1].query(l))+a[i][l])==BIT[i].query(l))) l++;
while(r<=n&&((max(BIT[i].query(r-1)+k,BIT[i-1].query(r))+a[i][r])!=BIT[i].query(r))) r++;
if(l>n) break;BIT[i].upd(l,k);BIT[i].upd(r,-k);ans+=(r-l)*k;
}
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("run.in","r",stdin);
freopen("run.out","w",stdout);
n=read();
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=read();
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=max(f[i-1][j],f[i][j-1])+a[i][j];
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){
BIT[i].upd(j , f[i][j]);
BIT[i].upd(j+1,-f[i][j]);
}
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) ans+=f[i][j];printf("%lld\n",ans);
for(int i=1,x,y;i<=n;i++){
scanf("%s",str+1);x=read(),y=read();
upd(x,y,((str[1]=='U')?(1):(-1)));
printf("%lld\n",ans);
}
return 0;
}
B. 算术
考虑整个 \(k\) 次剩余
只要检验 \(n\) 是否存在 \(k\) 次剩余即可
可以选择若干个模数 \(P\) ,若都存在 \(k\) 次剩余
则 \(n\) 可能存在,若有一个不存在那 \(n\) 一定不存在 \(k\) 次剩余
那么考虑如何检验
如果模数形如 \(ak+1\)
那么 \(x^{ak}\equiv 1(\text{mod }P)\)
又因为 \(x^k=n\) 所以 \(n^a\equiv 1(\text{mod }P)\)
这样就方便检验了
Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int T,k,c,n,len,mod;
char st[1000010];
bool jud;
inline int check(int x){for(int i=2;i*i<=x;i++) if(x%i==0) return false;return true;}
inline void getn(){n=0;for(int i=1;i<=len;i++) n=(n*10+st[i]-'0')%mod;}
inline int qpow(int x,int k){
int res=1,base=x;
while(k){if(k&1) res=res*base%mod;base=base*base%mod;k>>=1;}
return res;
}
inline void solve(){
scanf("%s",st+1);len=strlen(st+1);k=read();c=0;jud=1;
for(int i=800;;i++) if(check(i*k+1)){
mod=i*k+1;getn();
if(qpow(n,i)!=1) jud=0;if(!jud) break;
c++;if(c==10) break;
}
puts(jud?"Y":"N");
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("math.in","r",stdin);
freopen("math.out","w",stdout);
T=read();while(T--) solve();
return 0;
}
C. 求和
暴力乱搞
考虑答案出现的位置 \(x,y\)
如果修改的位置为其中一个,分类讨论修改后的值是变大还是变小
变大的话直接给答案加,变小的话全局暴力查
如果修改的是其他位置,还是这么分类讨论
变大的话就查询一下周围的 \(k\) 个值,再和答案比较
变小的话就只修改值
正解的话就是维护以 \(a_i\) 为区间最大值的所有对数
修改时只考虑可能对答案有影响的位置
先查询 \(a_i\) 左右两边的 \(K\) 个区间的最大值,和 \(a_i\) 进行比较,如果比 \(a_i\) 要小,就更新 \(i\) 这个位置
否则就更新最大值的位置,然后再查询左右 \(K\) 个的值
如果他是最大值那就更新这个位置,否则不更新这个位置
Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define lson rt<<1
#define rson rt<<1|1
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,K,q,op,p;
int ans,x,y;
int a[1000010];
pair<int,int> t[1000010];
struct seg{int mx,pos;}st[1000010*4],t1,t2;
inline void pushup(int rt){
st[rt].mx=max(st[lson].mx,st[rson].mx);
if(st[rt].mx==st[lson].mx) st[rt].pos=st[lson].pos;
if(st[rt].mx==st[rson].mx) st[rt].pos=st[rson].pos;
}
void build(int rt,int l,int r){
if(l==r) return st[rt].mx=a[l],st[rt].pos=l,void();
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(rt);
}
void upd(int rt,int l,int r,int pos,int k){
if(l==r) return st[rt].mx=k,void();
int mid=(l+r)>>1;
if(pos<=mid) upd(lson,l,mid,pos,k);
else upd(rson,mid+1,r,pos,k);
pushup(rt);
}
seg query(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R) return st[rt];
int mid=(l+r)>>1;seg res,t;res.mx=-inf,res.pos=0;
if(L<=mid){
t=query(lson,l,mid,L,R);
res.mx=max(res.mx,t.mx);if(res.mx==t.mx) res.pos=t.pos;
}
if(R>mid){
t=query(rson,mid+1,r,L,R);
res.mx=max(res.mx,t.mx);if(res.mx==t.mx) res.pos=t.pos;
}
return res;
}
inline void solve(){
ans=-inf;
for(int i=1,l,r;i<=n;i++){
t1=query(1,1,n,1,n);if(t1.mx*2<=ans) break;
t[++p]=make_pair(t1.pos,t1.mx);upd(1,1,n,t1.pos,-inf);
l=max(t1.pos-K,1ll);r=min(t1.pos+K,n);
t2=query(1,1,n,l,r);
ans=max(ans,t1.mx+t2.mx);if(ans==t1.mx+t2.mx) x=t1.pos,y=t2.pos;
}
while(p){upd(1,1,n,t[p].first,t[p].second);p--;}
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
n=read(),K=read(),q=read(),op=read();
for(int i=1;i<=n;i++) a[i]=read();
build(1,1,n);solve();printf("%lld\n",ans);
for(int i=1,pos,k,l,r;i<=q;i++){
pos=read()^(op*ans),k=read()^(op*ans);
if(pos==x||pos==y){
if(a[pos]>k){upd(1,1,n,pos,k);solve();}
else{ans+=k-a[pos];upd(1,1,n,pos,k);}
}else{
if(a[pos]>k){
upd(1,1,n,pos,k);
}else{
upd(1,1,n,pos,-inf);
l=max(pos-K,1ll);r=min(pos+K,n);
t1=query(1,1,n,l,r);
ans=max(ans,t1.mx+k);
if(ans==t1.mx+k) x=t1.pos,y=pos;
upd(1,1,n,pos,k);
}
}
a[pos]=k;
printf("%lld\n",ans);
}
return 0;
}