【HNOI2019】部分题简要题解
题意懒得写了
LOJ
Day 1 T1 鱼
个人做法比较猎奇,如果有哪位大佬会证明能分享一下的话感激不尽。
题解:枚举鱼尾和鱼身的交点D,将所有其他点按照到D的距离排序,距离相同的分一组。
感性的理解,对于每个点D,暴力枚举距离相等的点对(B,C)。这样总的数量不会很多。感觉仍然是\(O(n^2)\)级别的。
那么我们对枚举的D,将所有的点对的中垂射线和点按照极角排序,扫一圈就能得到答案了。鱼尾的部分也是利用扫描线,用叉积判断可能会有问题(转过了180度),那么我们可以将其倍长,用极角的值来判即可。
精度要求比较高。
奇丑无比...
#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 2005
#define M 1000005
#define LL long long
#define LT long double
using namespace std;
int n;
LL ans;
//geometry
long double sqr(LL x)
{
LT v=x;
return v*v;
}
namespace geometry
{
const long double pi=acos(-1);
const long double eps=1e-15;
struct node
{
LL x,y;
node(LL _x=0,LL _y=0){x=_x,y=_y;}
};
node operator +(node x,node y) {return node(x.x+y.x,x.y+y.y);}
node operator -(node x,node y) {return node(x.x-y.x,x.y-y.y);}
long double angel(node x)
{
long double v=atan2(x.y,x.x);
if(v<0) v+=2*pi;
return v;
}
LT dis2(node x,node y) {return sqr(x.x-y.x)+sqr(x.y-y.y);}
LT crs(node x,node y)
{
return (LT)x.x*(LT)y.y-(LT)x.y*(LT)y.x;
}
}
using namespace geometry;
node d[N],a[N],dw[M];
LL c1[N],cnt[N];
LT ds[N];
int n1,px[N],fr[N],l,le;
vector<int> pt[N];
long double ag(int x)
{
if(x>l) return angel(d[px[x]])+2*pi;
else return angel(d[px[x]]);
}
int pw(node x)
{
if(x.x>=0) return (x.y>=0)?1:4;
else return (x.y>=0)?2:3;
}
bool cmp(int x,int y) {return ds[x]<ds[y];}
bool cmp2(node x,node y)
{
int fx=pw(x),fy=pw(y);
return (fx<fy||(fx==fy&&crs(x,y)>0));
}
bool cmp3(int x,int y) {return cmp2(d[x],d[y]);}
bool cmp4(node x,node y) {return dis2(x,node(0,0))<dis2(y,node(0,0));}
bool eql(node x,node y)
{
return(!cmp2(x,y)&&!cmp2(y,x));
}
int ed[N],mx,mn;
LL query(int k)
{
l=0;
fo(i,1,n)
if(i!=k)
{
d[++l]=a[i]-a[k];
px[l]=l;
ds[l]=dis2(a[i],a[k]);
}
sort(px+1,px+l+1,cmp);
n1=0;
fo(i,1,l)
{
if(i==1||abs(ds[px[i]]-ds[px[i-1]])>eps)
{
cnt[++n1]=0;
pt[n1].clear();
}
cnt[n1]++,pt[n1].push_back(px[i]),fr[px[i]]=n1;
}
if(l<5) return 0;
le=0;
fo(i,1,n1)
{
fo(j,0,cnt[i]-1)
{
fo(k,j+1,cnt[i]-1)
{
int u=pt[i][j],v=pt[i][k];
if((d[u]+d[v]).x!=0||(d[u]+d[v]).y!=0) dw[++le]=d[u]+d[v];
}
}
}
memset(c1,0,sizeof(c1));
sort(px+1,px+l+1,cmp3);
sort(dw+1,dw+le+1,cmp2);
int lst=0;
fo(i,1,l)
{
if(i==1||!eql(d[px[i]],d[px[i-1]]))
{
if(lst!=0)
{
sort(px+lst,px+i,cmp);
fo(j,lst,i-1) ed[j]=i-1;
}
lst=i;
}
}
if(lst!=0)
{
sort(px+lst,px+l+1,cmp);
fo(j,lst,l) ed[j]=l;
}
lst=0;
fo(i,1,le)
{
if(i==1||!eql(dw[i],dw[i-1]))
{
if(lst!=0) sort(dw+lst,dw+i,cmp4);
lst=i;
}
}
if(lst!=0) sort(dw+lst,dw+le+1,cmp4);
int lp=1,rp=1;
LL s1=0,sp=0;
fo(i,1,l) px[i+l]=px[i];
long double upg=angel(dw[1])+pi/2,dpg=angel(dw[1])+3*pi/2;
while(lp<=2*l&&ag(lp)<upg+eps) lp++;
rp=lp;
while(rp<=2*l&&ag(rp)<dpg) rp++;
for(int j=lp;j<rp;j++)
{
sp-=(LL)c1[fr[px[j]]]*(LL)(c1[fr[px[j]]]-1);
c1[fr[px[j]]]++;
sp+=(LL)c1[fr[px[j]]]*(LL)(c1[fr[px[j]]]-1);
}
int j=1,ef=0;
while(j<=l&&cmp2(d[px[j]],dw[1])) j++;
if(j<=l&&eql(d[px[j]],dw[1])) ef=ed[j];
else ef=0;
LT di=dis2(dw[1],node(0,0));
while(j<=ef&&di>=(LT)4*ds[px[j]]) j++;
if(ef!=0) s1=s1+sp*(LL)2*(LL)(ef-j+1);
mx=max(mx,le),mn=max(mn,n1);
fo(i,2,le)
{
if(i==1||!eql(dw[i],dw[i-1]))
{
upg=angel(dw[i])+pi/2,dpg=angel(dw[i])+3*pi/2;
while(rp<=2*l&&ag(rp)<dpg-eps)
{
sp-=(LL)c1[fr[px[rp]]]*(LL)(c1[fr[px[rp]]]-1);
c1[fr[px[rp]]]++;
sp+=(LL)c1[fr[px[rp]]]*(LL)(c1[fr[px[rp]]]-1);
rp++;
}
while(lp<=2*l&&ag(lp)<upg+eps)
{
sp-=(LL)c1[fr[px[lp]]]*(LL)(c1[fr[px[lp]]]-1);
c1[fr[px[lp]]]--;
sp+=(LL)c1[fr[px[lp]]]*(LL)(c1[fr[px[lp]]]-1);
lp++;
}
while(j<=l&&cmp2(d[px[j]],dw[i])) j++;
if(j<=l&&eql(d[px[j]],dw[i])) ef=ed[j];
else ef=0;
}
LT di=dis2(dw[i],node(0,0));
while(j<=ef&&di>=(LT)4*ds[px[j]]) j++;
if(ef!=0) s1=s1+sp*(LL)2*(LL)(ef-j+1);
}
return s1;
}
int main()
{
cin>>n;
fo(i,1,n) scanf("%lld%lld\n",&a[i].x,&a[i].y);
ans=0;
fo(i,1,n)
{
ans+=query(i);
}
printf("%lld\n",ans);
}
Day 1 T3 多边形
题解:观察样例可以发现,最终状态一定是n-3条边都与n号点相连。
那么次数最少的操作一定每一次都是要连到n的
进一步可以发现,某些边的操作一定在某条边之后,先后关系可以构成一个森林。
操作次数就是森林点数,方案数就是森林的拓扑序种数。
现在提前给出一些操作,观察这些操作在树上的变化,要么直接删去一个点,要么改变一些父子关系,改变的个数只有常数个,直接计算这些点对答案的影响即可。
用map来存标号,时间复杂度\(O(n\log n)\)
#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 100005
#define mo 1000000007
#define LL long long
using namespace std;
int mx[N],mi[N],n,m,n1,tp,ft[N],fn[N],t[N][2],ap[N][2],sz[N];
map<int,int> h[N];
LL f[N],js[N],ns[N],ny[N];
bool bz[N];
LL C(int n,int m)
{
if(n<m) return 0;
return js[n]*ns[m]%mo*ns[n-m]%mo;
}
LL nC(int n,int m)
{
if(n<m) return 0;
return ns[n]*js[m]%mo*js[n-m]%mo;
}
void dfs(int k)
{
if(!k) return;
dfs(t[k][0]),dfs(t[k][1]);
sz[k]+=sz[t[k][0]]+sz[t[k][1]];
f[k]=f[t[k][0]]*f[t[k][1]]%mo*C(sz[k]-1,sz[t[k][0]])%mo;
}
LL ksm(LL k,LL n)
{
LL s=1;
for(;n;n>>=1,k=k*k%mo) if(n&1) s=s*k%mo;
return s;
}
int main()
{
freopen("polygon.in","r",stdin);
freopen("polygon.out","w",stdout);
cin>>tp;
cin>>n;
js[0]=ns[0]=js[1]=ns[1]=ny[1]=1;
fo(i,2,n) js[i]=js[i-1]*(LL)i%mo,ny[i]=(-ny[mo%i]*(LL)(mo/i)%mo+mo)%mo;
fo(i,2,n) ns[i]=ns[i-1]*ny[i]%mo;
memset(mi,107,sizeof(mi));
fo(i,1,n-3)
{
int x,y;
scanf("%d%d",&x,&y);
if(x>y) swap(x,y);
if(y==n) {bz[i]=1;continue;}
ap[i][0]=x,ap[i][1]=y;
h[x][y]=i,h[y][x]=i;
mx[x]=max(mx[x],y),mx[y]=max(mx[y],x);
mi[x]=min(mi[x],y),mi[y]=min(mi[y],x);
}
fo(i,1,n-3)
{
int x=ap[i][0],y=ap[i][1];
if(bz[i]) continue;
n1++,sz[i]=1;
if(mx[x]>y)
{
int w=(*h[x].upper_bound(y)).second;
if(bz[w]) continue;
ft[i]=w,fn[i]=0,t[w][0]=i;
}
else if(mi[y]<x)
{
map<int,int>::iterator it=h[y].find(x);it--;
int w=(*it).second;
if(bz[w]) continue;
ft[i]=w,fn[i]=1,t[w][1]=i;
}
}
f[0]=1;
LL ans=1,sp=0;
fo(i,1,n-3)
if(!bz[i]&&!ft[i])
{
dfs(i);
sp+=sz[i];
ans=ans*f[i]%mo*C(sp,sz[i])%mo;
}
printf("%d",n1);
if(tp) printf(" %lld",ans);
printf("\n");
cin>>m;
fo(i,1,m)
{
int x,y,w;
scanf("%d%d",&x,&y);
w=h[x][y];
int n2=n1;LL s1=ans;
if(!ft[w])
{
n2--;
s1=s1*nC(sp,sz[w])%mo*ksm(f[w],mo-2)%mo;
s1=s1*C(sp-1-sz[t[w][0]],sz[t[w][1]])%mo*f[t[w][1]]%mo;
s1=s1*C(sp-1,sz[t[w][0]])%mo*f[t[w][0]]%mo;
}
else
{
int r=ft[w],p=fn[w];
if(p!=0) printf("WA\n");
s1=s1*ksm(f[r],mo-2)%mo;
s1=s1*f[t[w][1]]%mo*f[t[r][1]]%mo*C(sz[t[w][1]]+sz[t[r][1]],sz[t[w][1]])%mo*f[t[w][0]]%mo*C(sz[r]-1,sz[t[w][0]])%mo;
}
printf("%d",n2);
if(tp) printf(" %lld",s1);
printf("\n");
}
}
Day 2 T1 校园旅行
题解:考虑一个暴力DP,\(f[x][y]\)表示x,y是否能通过回文串到达,枚举两边的出边,按照BFS的顺序转移,时间复杂度\(O(m^2)\)
考虑优化,我们将边分类,要么是连接不同颜色的边,要么是连接相同颜色的边。
只取出连接相同颜色的边,考虑每一个连通块,如果它是个二分图,那么保留一棵生成树即可(因为匹配配只与奇偶性有关,数量不同可以在一条边反复横跳满足)。如果不是,那么奇偶性可以改变,可以任意匹配,那么保留一棵生成树,再连上一个自环表示奇环的情况。对于连接不同颜色的边的联通块,它显然是二分图,直接保留生成树即可。
连边采用并查集,时间复杂度\(O(m\alpha(n))\)
这样边数也降为了\(O(n)\)级别,暴力DP的时间复杂度就变成了\(O(n^2)\)
#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 5005
#define L 25000005
using namespace std;
int q,n,m,c[N],cnt,lp,m1;
bool f[N][N];
int d[L][2],f1[N],g[N],a[N][2][N],le;
bool bp[N],bc[N];
void bfs()
{
fo(i,1,n) f[i][i]=1,d[++le][0]=i,d[le][1]=i;
int l=0,r=le;
while(l<r)
{
l++;
int x=d[l][0],y=d[l][1];
fo(e,0,1)
{
fo(i,1,a[x][e][0])
{
int u=a[x][e][i];
fo(j,1,a[y][e][0])
{
int v=a[y][e][j];
if(!f[u][v]) f[u][v]=f[v][u]=1,d[++r][0]=u,d[r][1]=v;
}
}
}
}
n++,n--;
}
int getf(int k)
{
if(f1[k]==k||!f1[k]) return k;
int p=getf(f1[k]);
bc[k]^=bc[f1[k]];
return f1[k]=p;
}
int getf1(int k)
{
if(g[k]==k||!g[k]) return k;
return g[k]=getf1(g[k]);
}
void link(int x,int y)
{
a[x][c[y]][++a[x][c[y]][0]]=y;
}
int main()
{
freopen("tour.in","r",stdin);
freopen("tour.out","w",stdout);
cin>>n>>m>>q;
scanf("\n");
fo(i,1,n)
{
char ch=getchar();
c[i]=ch-'0';
}
fo(i,1,m)
{
int x,y;
scanf("%d%d",&x,&y);
if(c[x]==c[y])
{
int fx=getf(x),fy=getf(y);
if(fx!=fy)
{
f1[fy]=fx,bp[fx]|=bp[fy],bc[fy]=bc[x]^1^bc[y]^bc[fx];
link(x,y),link(y,x);
f[x][y]=f[y][x]=1;
d[++le][0]=x,d[le][1]=y;
}
else if(bc[x]==bc[y]) bp[fx]=1;
}
else
{
int fx=getf1(x),fy=getf1(y);
if(fx!=fy) g[fy]=fx,link(x,y),link(y,x);
}
}
fo(i,1,n) if(getf(i)==i&&bp[i]) link(i,i);
bfs();
fo(i,1,q)
{
int x,y;
scanf("%d%d",&x,&y);
if(f[x][y]) printf("YES\n");
else printf("NO\n");
}
}
Day 2 T2 白兔之舞
考虑枚举走了i步,容易得出\(Ans_t=\sum\limits_{i=0}^{L}[(i-t)\%k==0]{L\choose i}W^i_{x,y}\)
根据单位根反演的公式\([n|k]={1\over n}\sum\limits_{i=0}^{n-1}\omega_n^{ki}\)
这里单位根我们找一个p的原根,然后取其(p-1)/k次作为K次单位根
代入,交换主体可得
\(Ans_t=\sum\limits_{j=0}^{k-1}\omega_k^{-jt}\sum\limits_{i=0}^{L}{L\choose i}\left(\omega_k^j\right)^iW^i_{x,y}\)
后面的部分用二项式定理就是\(\left(\omega_k^jW+I\right)^L_{x,y}\),枚举j,用矩阵快速幂做
前面的\(\omega_k^{-jt}\),一个经典的套路就是将\(jt\)拆成\({j+t\choose 2}-{j\choose 2}-{t\choose 2}\)
这样剩下的就是一个卷积了,用任意模数NTT/MTT优化即可。
时间复杂度\(O(n^3k\log L+k\log k)\)
#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 3
#define M 262144
#define L 18
#define LL long long
using namespace std;
int n,m,r,st,ed,mo,P;
LL wp[M+1];
int d[100];
LL ksm(LL k,LL n)
{
LL s=1;
for(;n;n>>=1,k=k*k%mo) if(n&1) s=s*k%mo;
return s;
}
bool pd(LL v)
{
fo(i,1,d[0]) if(ksm(v,(mo-1)/d[i])==1) return 0;
return 1;
}
namespace polynomial
{
const double pi=acos(-1);
struct Z
{
double x,y;
Z(double _x=0,double _y=0){x=_x,y=_y;}
};
Z operator +(Z a,Z b) {return Z(a.x+b.x,a.y+b.y);}
Z operator -(Z a,Z b) {return Z(a.x-b.x,a.y-b.y);}
Z operator *(Z a,Z b) {return Z(a.x*b.x-a.y*b.y,a.y*b.x+a.x*b.y);}
Z wi[M+1],u1[M+1],u2[M+1],u3[M+1],u4[M+1],ux[M+1],uy[M+1];
int bit[M+1];
void prp()
{
fo(i,0,M)
{
bit[i]=(bit[i>>1]>>1)|((i&1)<<(L-1));
wi[i]=Z(cos(i*2*pi/M),sin(i*2*pi/M));
}
}
void DFT(Z *a,bool pd)
{
fo(i,0,M-1) if(i<bit[i]) swap(a[i],a[bit[i]]);
Z v;
for(int h=1,m=2,l=M>>1;m<=M;l>>=1,h=m,m<<=1)
{
for(int j=0;j<M;j+=m)
{
Z *x=a+j,*y=a+j+h,*w=(!pd)?wi:wi+M;
fo(i,0,h-1)
{
Z v=*y * *w;
*y=*x-v,*x=*x+v;
x++,y++,w+=(!pd)?l:-l;
}
}
}
if(pd) fo(i,0,M-1) a[i].x/=M,a[i].y/=M;
}
void rec(Z *a,Z *x,Z *y)
{
fo(i,0,M-1)
{
x[i].x=(a[i].x+a[(M-i)%M].x)/2;
x[i].y=(a[i].y-a[(M-i)%M].y)/2;
y[i].x=(a[i].y+a[(M-i)%M].y)/2;
y[i].y=(a[(M-i)%M].x-a[i].x)/2;
}
}
void mul(LL *a,LL *b)
{
fo(i,0,M-1) ux[i]=uy[i]=u1[i]=u2[i]=u3[i]=u4[i]=Z(0,0);
fo(i,0,M-1)
{
ux[i].x=a[i]/P,ux[i].y=a[i]%P;
uy[i].x=b[i]/P,uy[i].y=b[i]%P;
}
prp();
DFT(ux,0),DFT(uy,0);
rec(ux,u1,u2),rec(uy,u3,u4);
fo(i,0,M-1)
{
ux[i]=u1[i]*u3[i]+(u1[i]*u4[i])*Z(0,1);
uy[i]=u2[i]*u4[i]+(u2[i]*u3[i])*Z(0,1);
}
DFT(ux,1),DFT(uy,1);
fo(i,0,M-1)
{
LL u=ux[i].x+mo+0.5,v=ux[i].y+mo+0.5,p=uy[i].y+mo+0.5,q=uy[i].x+mo+0.5;
u%=mo,v%=mo,p%=mo,q%=mo;
a[i]=((u*P%mo*P%mo+(v+p)%mo*P%mo+q)%mo+mo)%mo;
}
}
}
using namespace polynomial;
namespace matrix
{
struct MT
{
LL a[3][3];
}ac,ua;
MT operator *(MT &a,MT &b)
{
MT c;
memset(c.a,0,sizeof(c.a));
fo(i,0,n-1)
fo(k,0,n-1)
fo(j,0,n-1) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mo;
return c;
}
MT kst(MT &a,LL x)
{
MT s;
memset(s.a,0,sizeof(s.a));
fo(i,0,n-1) s.a[i][i]=1;
for(;x;x>>=1,a=a*a) if(x&1) s=s*a;
return s;
}
}
using namespace matrix;
LL a[M+1],b[M+1];
int main()
{
freopen("dance.in","r",stdin);
freopen("dance.out","w",stdout);
cin>>n>>m>>r>>st>>ed>>mo;
P=sqrt(mo);
fo(i,0,n-1) fo(j,0,n-1) scanf("%lld",&ac.a[i][j]);
int n1=mo-1;
fo(i,2,P)
{
if(n1%i==0)
{
d[++d[0]]=i;
while(n1%i==0) n1/=i;
}
}
wp[0]=1;
for(wp[1]=2;!pd(wp[1]);wp[1]++);
wp[1]=ksm(wp[1],(mo-1)/m);
fo(i,2,m) wp[i]=wp[i-1]*wp[1]%mo;
fo(i,0,m-1)
{
fo(x,0,n-1) fo(y,0,n-1) ua.a[x][y]=ac.a[x][y]*wp[i]%mo;
fo(x,0,n-1) ua.a[x][x]++;
ua=kst(ua,r);
a[i]=ua.a[st-1][ed-1]*wp[(LL)i*(LL)(i-1)/2%m]%mo;
}
fo(i,0,2*m-2) b[2*m-i]=wp[(m-(LL)i*(LL)(i-1)/2%m)%m];
mul(a,b);
LL ns=ksm(m,mo-2);
fo(i,0,m-1) printf("%lld\n",wp[(LL)i*(LL)(i-1)/2%m]*ns%mo*a[2*m-i]%mo);
}
Day 2 T3 序列
题解:可以发现,最优策略是将原序列分成若干段,每一段取它们的均值,并且均值应该递增。
进一步的,记S[i]为a的1~i前缀和,我们将点\((i,S[i])\)放到平面上,求一个下凸壳,相邻点的连线斜率就是这一段取的均值。用单调栈来做,就可以做到\(O(nm)\)了
考虑优化,修改一个位置相当于后缀的所有点整体下移/上移,我们预处理出前缀凸壳和后缀凸壳(单调栈构成树形结构,总的个数是\(O(n)\)的),现在相当于做一个凸壳合并,我们在前缀凸壳上二分,再相应的在后缀凸壳上二分找到最左的一个连接后满足下凸性的点,判断前缀凸壳此时是否也是凸的相应修改二分区间即可。(二分实际上可以用树上倍增来实现)
时间复杂度\(O(m\log ^2n)\)
实现上细节比较多
#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 100005
#define LL long long
#define LT unsigned long long
#define mo 998244353
using namespace std;
LL a[N],ny[N],s2[N],sm[N],sr[N],ans[N];
LT s[N];
int n,m,st[N],top,f[N][19],ask[N][2],qs[N];
bool pd(int x,int y,int z)
{
return (s[y]-s[x])*(LT)(z-y)>(s[z]-s[y])*(LT)(y-x);
}
bool pd2(int x,int y,int z,LL xd)
{
return (s[y]-s[x]+xd)*(LT)(z-y)>(s[z]-s[y])*(LT)(y-x);
}
bool pd3(int x,int y,int z,LL xd)
{
return (s[y]-s[x])*(LT)(z-y)>(s[z]-s[y]+xd)*(LT)(y-x);
}
LL calc(LL v,int x,int y)
{
if(x>=y) return 0;
return ((s2[y]-s2[x]+mo)%mo+v*v%mo*(LL)(y-x)%mo-(LL)2*((s[y]-s[x])%mo)%mo*v%mo+mo+mo)%mo;
}
LL calc2(LL v,int x,int y,int k,LL xd)
{
if(x>=y) return 0;
LL u=(s2[y]-s2[x]-a[k]*a[k]%mo+(a[k]+xd)*(a[k]+xd)%mo+mo+mo)%mo;
return (u+v*v%mo*(LL)(y-x)%mo-((LL)2*((LL)((s[y]-s[x])%mo)+xd)%mo*v%mo+mo)%mo+mo)%mo;
}
bool pd1(int x,int y,LL xd,int k)
{
int l=1,r=top,mid;
while(l+1<r)
{
mid=(l+r)>>1;
if(pd2(y,st[mid],st[mid-1],xd)) r=mid;
else l=mid;
}
if(r<=l||!pd2(y,st[r],st[r-1],xd)) mid=r;
else mid=l;
return (!pd3(x,y,st[mid],xd));
}
int wz(int y,LL xd,int k)
{
int l=1,r=top,mid;
while(l+1<r)
{
mid=(l+r)>>1;
if(pd2(y,st[mid],st[mid-1],xd)) r=mid;
else l=mid;
}
if(r<=l||!pd2(y,st[r],st[r-1],xd)) mid=r;
else mid=l;
return st[mid];
}
LL query(int k,LL xd)
{
int p=f[k-1][0],q=k-1;
for(int j=18;q>0&&!pd1(p,q,xd,k);)
{
while(j&&pd1(f[p][j],f[q][j],xd,k)) j--;
p=f[p][j],q=f[q][j];
}
int w=wz(q,xd,k);LL v=(s[w]-s[q]+xd)%mo*ny[w-q]%mo;
return (calc(v,q,k-1)+calc2(v,k-1,w,k,xd)+sm[q]+sr[w])%mo;
}
bool cmp(int x,int y)
{
return ask[x][0]<ask[y][0];
}
int main()
{
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
cin>>n>>m;
st[++top]=0;
ny[1]=1;
fo(i,2,n) ny[i]=(-ny[mo%i]*(LL)(mo/i)%mo+mo)%mo;
fo(i,1,n) scanf("%lld",&a[i]),s[i]=s[i-1]+a[i],s2[i]=(s2[i-1]+a[i]*a[i]%mo)%mo;
st[top=1]=0;
fo(i,1,n)
{
while(top>1&&pd(st[top-1],st[top],i)) top--;
st[++top]=i;
f[i][0]=st[top-1];
sm[i]=(sm[f[i][0]]+calc((s[i]-s[f[i][0]])%mo*ny[i-f[i][0]]%mo,f[i][0],i))%mo;
}
fo(j,1,18) fo(i,1,n) f[i][j]=f[f[i][j-1]][j-1];
printf("%lld\n",sm[n]);
fo(i,1,m)
{
scanf("%d%d",&ask[i][0],&ask[i][1]);
qs[i]=i;
}
sort(qs+1,qs+m+1,cmp);
memset(st,0,sizeof(st)),top=0;
int j=m;
fod(i,n,1)
{
while(top>1&&pd(i,st[top],st[top-1])) top--;
st[++top]=i;
sr[i]=sr[st[top-1]];
if(top>1) sr[i]=(sr[i]+calc((s[st[top-1]]-s[i])%mo*ny[st[top-1]-i]%mo,i,st[top-1]))%mo;
while(j>0&&ask[qs[j]][0]==i)
{
ans[qs[j]]=query(i,ask[qs[j]][1]-a[i]);
j--;
}
}
fo(i,1,m) printf("%lld\n",ans[i]);
}
【HNOI2019】部分题简要题解的更多相关文章
- HDU100题简要题解(2060~2069)
这十题感觉是100题内相对较为麻烦的,有点搞我心态... HDU2060 Snooker 题目链接 Problem Description background: Philip likes to pl ...
- HDU100题简要题解(2080~2089)
//2089之前忘做了,周二C语言课上做,至于2086,写题解的时候突然发现之前的做法是错的,新的解法交上去CE,等周二再弄吧,其余题目暂时可以放心 HDU2080 夹角有多大II 题目链接 Prob ...
- HDU100题简要题解(2070~2079)
HDU2070 Fibbonacci Number 题目链接 Problem Description Your objective for this question is to develop a ...
- HDU100题简要题解(2050~2059)
HDU2050 折线分割平面 题目链接 Problem Description 我们看到过很多直线分割平面的题目,今天的这个题目稍微有些变化,我们要求的是n条折线分割平面的最大数目.比如,一条折线可以 ...
- HDU100题简要题解(2000~2009)
前言(废话): 从11月6号到11月20号,断断续续做了有三个星期,总算整完了,之后会慢慢整理汇总到这里 中间部分用到数学知识的十几道题边学边做直接把我这个数学菜鸟做到怀疑人生 11.6~11.10又 ...
- 【NOI2019十二省联合省选】部分题简要题解
Day 1 T1 异或粽子 题意:给出一个长为n的序列,选择K个不完全重合的区间使得每个区间的异或值的总和最大. 题解:先做一个前缀异或和,对于每一个右端点我们记录三元组(l,r,x)表示在左端点在\ ...
- HDU100题简要题解(2040~2049)
HDU2040 亲和数 题目链接 Problem Description 古希腊数学家毕达哥拉斯在自然数研究中发现,220的所有真约数(即不是自身的约数)之和为: 1+2+4+5+10+11+20+2 ...
- HDU100题简要题解(2030~2039)
HDU2030 汉字统计 题目链接 Problem Description 统计给定文本文件中汉字的个数. Input 输入文件首先包含一个整数n,表示测试实例的个数,然后是n段文本. Output ...
- HDU100题简要题解(2020~2029)
HDU2020 绝对值排序 题目链接 Problem Description 输入n(n<=100)个整数,按照绝对值从大到小排序后输出.题目保证对于每一个测试实例,所有的数的绝对值都不相等. ...
随机推荐
- Go基本数据类型
Go基本数据类型 第一部分:基本数据类型和操作符 1. 文件名&关键字&标识符 1. 所有go源码以.go结尾 2. 标识符以字母或下划线开头,大小写敏感,比如: a. boy b. ...
- 使用vim鼠标右键无法粘贴问题解决
问题: Debian中通过终端使用vim,无法通过鼠标粘贴.这是由于一项默认的鼠标配置导致. 解决方法: vi /usr/share/vim/vim80/defaults.vim 查找set mous ...
- 签名Android应用程序
Android要求对作为产品发布的应用进行签名(包名相同的化,后安装的应用会覆盖前面安装的应用) 签名作用:1.确定发布者的身份.2.确保应用的完整性. 注意:在应用的开发.调试阶段,Eclipse的 ...
- xcconfig
[xcconfig] 1.When you can use a .xcconfig file? Use .xcconfig files if you find yourself changing th ...
- Oracle 11g PL/SQL Developer登入时候报ORA-12638: 身份证明检索失败的解决办法(安装了6遍,吐血之作)
1.报这个错的时候会弹出一个对话框,先点击终止 2.然后汇报出这个是错误的窗口,然后点击确认,但是不要关这个安装窗口也不要其他不必要操作,窗口最小化 3.找到product文件夹,一般在app文件里 ...
- 前端福利之overflow-scrol 怎么隐藏滚动条(转)
最近用vue写wap站的时候遇到了微信打开页面滚动条无法隐藏的问题. 对于隐藏滚动条,我们最常用的方法首先是: 1.使用以下CSS可以隐藏滚动条: .container::-webkit-scroll ...
- javascript 深度克隆
关键词 :递归 主要分为 数组 .对象.以及基本类型 function clone(Obj) { var buf; if (Obj instanceof Arr ...
- linux 用户/用户组添加修改删除(ubuntu/centos)
一.LINUX(UBUNTU/CENTOS)用户添加删除修改 1.建用户: adduser web //新建web用户 useradd web ...
- MySQL 笔记整理(20) --幻读是什么,幻读有什么问题?
笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 20) --幻读是什么,幻读有什么问题? 我们先来看看表结构和初始化数据 ...
- [LeetCode 题解]: Rotate List
Given a list, rotate the list to the right by k places, where k is non-negative. For example:Given 1 ...