周六的比赛情况:
前两个小时做自己的c题,后来发现推不动,容斥复杂度过高,然后就转移阵地了。
之后:
助攻了k题,发现了题意读错了,然后修改之后过了。
助攻+完成了g题,一并推出容斥,并完成代码提交,代码:
#include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<cstdio> #define maxn 100010 using namespace std; const long long mo=1000000007; long long fun; bool vis[maxn]; long long prime[maxn]; long long inv2,inv3,inv6; long long fac[32]; long long box[32]; long long tot; long long total; long long n,m; long long qpow(long long x,long long y){ if (x==0)return 0; long long ans=1; long long k=x; while(y){ if(y&1)ans=ans*k%mo; k=k*k%mo; y>>=1; } return (ans+mo)%mo; } void getprime(){ long long i,j; tot=0; memset (vis,0,sizeof(vis)); for (i=2;i<maxn;i++){ if (!vis[i]){ prime[++tot]=i; for (j=i+i;j<maxn;j+=i){ vis[j]=1; } } } } long long getfac(long long x){ long long cnt=0; long long i; for (i=1;i<=tot&&prime[i]*prime[i]<=x;i++){ if(x%prime[i]==0){ fac[++cnt]=prime[i]; while(x%prime[i]==0){ x=x/prime[i]; } } } if(x>1) fac[++cnt]=x; return cnt; } long long cal(long long x,long long temp){ return (temp*x%mo*(x+1)%mo*inv2%mo+temp*temp%mo*x%mo*(x+1)%mo*(2*x+1)%mo*inv6%mo+mo)%mo; } void sfind(long long x,long long y,long long z,long long val){ long long i,j; for (i=x;i<=total;i++){ if (total-i<z-y)return ; box[y]=fac[i]; if (y==z){ long long temp=1; for (j=1;j<=z;j++){ temp=temp*box[j]; } fun=(fun+cal(n/temp,temp))%mo; } else sfind(i+1,y+1,z,val); } } long long solve(long long x){ long long i,j; long long temp=-1; long long ans=(x*(x+1)%mo*(x+2)%mo)*inv3%mo; for (i=1;i<=total;i++){ fun=0; sfind(1,1,i,x); ans=(ans+fun*temp%mo)%mo; temp=-temp; } return ans; } int main(){ long long i,j; getprime(); inv2=qpow(2,mo-2); inv3=qpow(3,mo-2); inv6=qpow(6,mo-2); while (scanf("%lld%lld",&n,&m)!=EOF){ total=getfac(m); long long ans=solve(n); cout<<(ans+mo)%mo<<endl; } }
助攻了i题,发现代码中复杂度过高的部分。
赛后发现c题可以用莫比乌斯函数优化,但是理解深度不够。
周天徐州站的比赛情况:
前一个半小时做自己的c题,后来发现时间复杂度不对(后群里说样例也水),然后转移阵地。
之后:
做出了h题,看到题意之后,想出来了完整的思路,并很快ac,总体是个双线段树+思维,代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define maxn 1000010
using namespace std;
long long a[maxn];
long long n;
struct xtree{
long long l,r;
long long sum;
long long mid(){
return (l+r)/2;
}
}tree[maxn];
void pushup(long long id){
tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
}
void build(long long id,long long l,long long r){
tree[id].l=l;
tree[id].r=r;
if (l==r){
tree[id].sum=a[l];
return ;
}
long long mid=tree[id].mid();
build(id*2,l,mid);
build(id*2+1,mid+1,r);
pushup(id);
}
void update(long long id,long long pos,long long val){
if (tree[id].l==tree[id].r){
tree[id].sum=val;
return ;
}
long long mid=tree[id].mid();
if (pos<=mid){
update(id*2,pos,val);
}
else {
update(id*2+1,pos,val);
}
pushup(id);
}
long long query(long long id,long long l,long long r){
if (tree[id].l>=l&&tree[id].r<=r){
return tree[id].sum;
}
long long mid=tree[id].mid();
if (r<=mid){
return query(id*2,l,r);
}
else if (l>mid){
return query(id*2+1,l,r);
}
else {
return query(id*2,l,mid)+query(id*2+1,mid+1,r);
}
}
struct xtree1{
long long l,r;
long long sum;
long long mid(){
return (l+r)/2;
}
}tree1[maxn];
void pushup1(long long id){
tree1[id].sum=tree1[id*2].sum+tree1[id*2+1].sum;
}
void build1(long long id,long long l,long long r){
tree1[id].l=l;
tree1[id].r=r;
if (l==r){
tree1[id].sum=(n-l+1)*a[l];
return ;
}
long long mid=tree1[id].mid();
build1(id*2,l,mid);
build1(id*2+1,mid+1,r);
pushup1(id);
}
void update1(long long id,long long pos,long long val){
if (tree1[id].l==tree1[id].r){
tree1[id].sum=(n-tree1[id].l+1)*val;
return ;
}
long long mid=tree1[id].mid();
if (pos<=mid){
update1(id*2,pos,val);
}
else {
update1(id*2+1,pos,val);
}
pushup1(id);
}
long long query1(long long id,long long l,long long r){
if (tree1[id].l>=l&&tree1[id].r<=r){
return tree1[id].sum;
}
long long mid=tree1[id].mid();
if (r<=mid){
return query1(id*2,l,r);
}
else if (l>mid){
return query1(id*2+1,l,r);
}
else {
return query1(id*2,l,mid)+query1(id*2+1,mid+1,r);
}
}
int main(){
long long i,j;
long long m,x,y,z;
while (scanf("%lld%lld",&n,&m)!=EOF){
for (i=1;i<=n;i++)scanf("%lld",&a[i]);
build(1,1,n);
build1(1,1,n);
while (m--){
long long flag;
scanf("%lld",&flag);
if (flag==1){
scanf("%lld%lld",&x,&y);
printf("%lld\n",query1(1,x,y)-(n-x+1-(y-x+1))*query(1,x,y));
}
else {
scanf("%lld%lld",&x,&y);
update(1,x,y);
update1(1,x,y);
}
}
}
}
做出了g题,被纪翔文告知了思路,后用双线段树+离散处理,因为我处理时间过长,纪翔文同时开了树状数组的写法,最后同时ac,代码:
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#define maxn 200010
#define maxx 10000010
using namespace std;
long long cntx[maxx];
long long cnty[maxx];
struct point{
long long x;
long long y;
long long id;
}p[maxn];
bool cmpx(point a,point b){
if(a.x<b.x)return 1;
else if(a.x==b.x){
if(a.y<b.y)return 1;
else return 0;
}
return 0;
}
bool cmpy(point a,point b){
if(a.y<b.y)return 1;
else if(a.y==b.y){
if(a.x<b.x)return 1;
else return 0;
}
return 0;
}
bool cmpid(point a,point b){
return a.id>b.id;
}
struct xtree{
long long l,r;
long long lazy;
long long sum;
long long mid(){
return (l+r)/2;
}
}treex[maxn];
void pushupx(long long id){
treex[id].sum=treex[id*2].sum+treex[id*2+1].sum;
}
void pushdownx(long long id){
if (treex[id].lazy){
treex[id*2].lazy=treex[id].lazy;
treex[id*2+1].lazy=treex[id].lazy;
long long mid=treex[id].mid();
treex[id*2].sum=treex[id].lazy*(mid-treex[id].l+1);
treex[id*2+1].sum=treex[id].lazy*(treex[id].r-mid);
treex[id].lazy=0;
}
}
void buildx(long long id,long long l,long long r){
treex[id].l=l;
treex[id].r=r;
treex[id].lazy=0;
if (l==r){
treex[id].sum=0;
return ;
}
long long mid=treex[id].mid();
buildx(id*2,l,mid);
buildx(id*2+1,mid+1,r);
pushupx(id);
}
void updatex(long long id,long long l,long long r,long long val){
if (treex[id].l>=l&&treex[id].r<=r){
treex[id].lazy=val;
treex[id].sum=(treex[id].r-treex[id].l+1)*val;
return ;
}
pushdownx(id);
long long mid=treex[id].mid();
if (r<=mid){
updatex(id*2,l,r,val);
}
else if (l>mid){
updatex(id*2+1,l,r,val);
}
else {
updatex(id*2,l,mid,val);
updatex(id*2+1,mid+1,r,val);
}
pushupx(id);
}
long long queryx(long long id,long long l,long long r){
if (treex[id].l>=l&&treex[id].r<=r){
return treex[id].sum;
}
pushdownx(id);
long long mid=treex[id].mid();
if (r<=mid){
return queryx(id*2,l,r);
}
else if (l>mid){
return queryx(id*2+1,l,r);
}
else {
return queryx(id*2,l,r)+queryx(id*2+1,l,r);
}
}
struct ytree{
long long l,r;
long long lazy;
long long sum;
long long mid(){
return (l+r)/2;
}
}treey[maxn];
void pushupy(long long id){
treey[id].sum=treey[id*2].sum+treey[id*2+1].sum;
}
void pushdowny(long long id){
if (treey[id].lazy){
treey[id*2].lazy=treey[id].lazy;
treey[id*2+1].lazy=treey[id].lazy;
long long mid=treey[id].mid();
treey[id*2].sum=treey[id].lazy*(mid-treey[id].l+1);
treey[id*2+1].sum=treey[id].lazy*(treey[id].r-mid);
treey[id].lazy=0;
}
}
void buildy(long long id,long long l,long long r){
treey[id].l=l;
treey[id].r=r;
treey[id].lazy=0;
if (l==r){
treey[id].sum=0;
return ;
}
long long mid=treey[id].mid();
buildy(id*2,l,mid);
buildy(id*2+1,mid+1,r);
pushupy(id);
}
void updatey(long long id,long long l,long long r,long long val){
if (treey[id].l>=l&&treey[id].r<=r){
treey[id].lazy=val;
treey[id].sum=(treey[id].r-treey[id].l+1)*val;
return ;
}
pushdowny(id);
long long mid=treey[id].mid();
if (r<=mid){
updatey(id*2,l,r,val);
}
else if (l>mid){
updatey(id*2+1,l,r,val);
}
else {
updatey(id*2,l,mid,val);
updatey(id*2+1,mid+1,r,val);
}
pushupy(id);
}
long long queryy(long long id,long long l,long long r){
if (treey[id].l>=l&&treey[id].r<=r){
return treey[id].sum;
}
pushdowny(id);
long long mid=treey[id].mid();
if (r<=mid){
return queryy(id*2,l,r);
}
else if (l>mid){
return queryy(id*2+1,l,r);
}
else {
return queryy(id*2,l,r)+queryy(id*2+1,l,r);
}
}
int main(){
long long n,x,y;
long long i;
while (scanf("%lld",&n)!=EOF){
for (i=1;i<=n;i++){
scanf("%lld%lld",&p[i].x,&p[i].y);
p[i].id=i;
}
sort (p+1,p+n+1,cmpx);
long long totx=1;
memset (cntx,0,sizeof(cntx));
memset (cnty,0,sizeof(cnty));
p[0].x=0;
p[0].y=0;
cntx[p[0].x]=1;
for (i=1;i<=n;i++){
if (p[i].x!=p[i-1].x){
cntx[p[i].x]=++totx;
}
}
buildx(1,1,totx);
cnty[p[0].y]=1;
long long toty=1;
sort (p+1,p+n+1,cmpy);
for (i=1;i<=n;i++){
if (p[i].y!=p[i-1].y){
cnty[p[i].y]=++toty;
}
}
buildy(1,1,toty);
sort (p+1,p+n+1,cmpid);
long long ansx=0;
long long ansy=0;
for (i=1;i<=n;i++){
long long tempx=queryx(1,cnty[p[i].y],cnty[p[i].y]);
ansx=ansx+p[i].x-tempx;
long long tempy=queryy(1,cntx[p[i].x],cntx[p[i].x]);
ansy=ansy+p[i].y-tempy;
updatex(1,cnty[tempy],cnty[p[i].y],p[i].x);
updatey(1,cntx[tempx],cntx[p[i].x],p[i].y);
}
cout<<ansx+ansy<<endl;
}
}
然后就废了,调两个双线段树的代码确实很耗费精力,加上上午上完数学物理方程课过来的,就觉得头很疼。