这次的题...很水...然而还是差点爆零
T1 题目简述:给定一个序列,求区间最大子段和(带修改操作)。
n<=500000,m<=100000
解题思路:线段树维护即可。(GSS3原题...数据范围都不变...出题人好懒)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define INF 0x3f3f3f3f using namespace std; int n,m,a[500010]; struct uio{ uio(){lmx=rmx=mx=-INF;} int lmx,rmx,mx,sum; }tree[2000010]; void pushup(int x) { int ls=(x<<1),rs=((x<<1)|1); tree[x].mx=max(tree[ls].rmx+tree[rs].lmx,max(tree[ls].mx,tree[rs].mx)); tree[x].lmx=max(tree[ls].lmx,tree[ls].sum+tree[rs].lmx); tree[x].rmx=max(tree[rs].rmx,tree[rs].sum+tree[ls].rmx); tree[x].sum=tree[ls].sum+tree[rs].sum; } void build(int now,int l,int r) { if(l==r) { tree[now].mx=tree[now].lmx=tree[now].rmx=tree[now].sum=a[l]; return; } int mid=(l+r)>>1; build((now<<1),l,mid); build(((now<<1)|1),mid+1,r); pushup(now); } void revise(int now,int l,int r,int to,int k) { if(l==r) { tree[now].mx=tree[now].lmx=tree[now].rmx=tree[now].sum=k; return; } int mid=(l+r)>>1; if(to<=mid) revise((now<<1),l,mid,to,k); else revise(((now<<1)|1),mid+1,r,to,k); pushup(now); } uio query(int now,int l,int r,int L,int R) { if(L<=l&&r<=R) return tree[now]; int mid=(l+r)>>1; if(L>mid) return query(((now<<1)|1),mid+1,r,L,R); if(R<=mid) return query((now<<1),l,mid,L,R); if(L<=mid&&mid<R) { uio ans; uio a=query((now<<1),l,mid,L,R); uio b=query(((now<<1)|1),mid+1,r,L,R); ans.mx=max(a.rmx+b.lmx,max(a.mx,b.mx)); ans.lmx=max(a.lmx,a.sum+b.lmx); ans.rmx=max(b.rmx,b.sum+a.rmx); ans.sum=a.sum+b.sum; return ans; } } int main() { freopen("BRS.in","r",stdin); freopen("BRS.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); if(u==2) revise(1,1,n,v,w); if(u==1) { if(v>w) swap(v,w); printf("%d\n",query(1,1,n,v,w).mx); } } return 0; }
T2 题意简述:有n个格子,每次最多走k个,问走到第n格有多少种走法。答案对7777777取模。
1<=n<=2^31-1,1<=k<=10
解题思路:一看n这么大,考虑矩阵加速。
发现递推过程类似斐波那契数列,因此构造矩阵如下。(以k=5为例)
0 0 0 0 1 0 1 0 0 1 0 0 1 0 1 0 0 0 1 1
然后求qpow(matrix.a,n)即可。
注:以下代码来自sdfzsyq大佬。(其实就是我懒...)
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define LL long long using namespace std; const int mod = 7777777; int n,k; struct Mat{ LL a[15][15]; Mat(){ memset(a,0,sizeof(a)); } Mat operator*(const Mat &h){ Mat c; for(register int i=1;i<=k;i++) for(register int j=1;j<=k;j++) for(register int o=1;o<=k;o++) (c.a[i][j]+=(a[i][o]%mod*h.a[o][j]%mod))%=mod; return c; } }f,ans,st; inline void fast_pow(Mat A,int b){ for(;b;b>>=1){ if(b&1) st=st*A; A=A*A; } } int main(){ freopen("fyfy.in","r",stdin); freopen("fyfy.out","w",stdout); scanf("%d%d",&k,&n); if(k==1){ puts("1"); return 0; } for(register int i=2;i<=k;i++) f.a[i][i-1]=1; for(register int i=1;i<=k;i++) f.a[i][k]=1; for(register int i=1;i<=k;i++) st.a[i][i]=1; fast_pow(f,n); printf("%lld\n",st.a[k][k]); return 0; }
T3 题意简述:求矩形面积并。
n<=100,坐标数值绝对值<=10^8
解题思路:扫描线。
由于数据太水,因此本题可以用O(n^2)水过。
坐在我旁边的erkkierkko大佬说n应该开到10^6。
如果按照erkkierkko大佬的数据范围,本题代码应加上线段树优化+卡常。
复杂度O(nlogn)。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define inf 100000001 #define INF 0x3f3f3f3f #define ll long long using namespace std; ll n,ans,a[210],sec[210][110],sec1[210][110],vis[110]; struct uio{ ll l,r,u,d; }mat[110]; struct oiu{ ll u,d; }tmp[110]; bool cmp(oiu x,oiu y) { if(x.u==y.u) return x.d>y.d; return x.u>y.u; } int main() { freopen("olddriver.in","r",stdin); freopen("olddriver.out","w",stdout); scanf("%lld",&n); for(ll i=1;i<=n;i++) { scanf("%lld%lld%lld%lld",&mat[i].l,&mat[i].d,&mat[i].r,&mat[i].u); a[i*2-1]=mat[i].l,a[i*2]=mat[i].r; } sort(a+1,a+1+2*n); ll num=unique(a+1,a+1+2*n)-a-1; for(ll i=1;i<=n;i++) { ll u=lower_bound(a+1,a+1+num,mat[i].l)-a; sec[u][++sec[u][0]]=i,sec1[u][++sec1[u][0]]=mat[i].l; ll v=lower_bound(a+1,a+1+num,mat[i].r)-a; sec[v][++sec[v][0]]=i,sec1[v][++sec1[v][0]]=mat[i].r; } for(ll i=1;i<=200;i++) { memset(tmp,0,sizeof(tmp)); ll cnt=0,num=0; ll j=1; while(sec[i][j]!=0) { if(!vis[sec[i][j]]) vis[sec[i][j]]=1; else vis[sec[i][j]]=0; j++; } for(ll k=1;k<=n;k++) if(vis[k]) tmp[++cnt].u=mat[k].u, tmp[cnt].d=mat[k].d; sort(tmp+1,tmp+1+cnt,cmp); ll mu=tmp[1].u,md=tmp[1].d; for(ll k=2;k<=cnt;k++) { if(tmp[k].u<md) num-=md-tmp[k].u; md=min(md,tmp[k].d); } num+=mu-md; ans+=num*(sec1[i+1][1]-sec1[i][1]); } printf("%lld\n",ans); return 0; }