SDOI2016 Round 1解题报告
来源:互联网 发布:中文域名交易平台 编辑:程序博客网 时间:2024/06/05 14:13
题目大意:
已知
题解:
可以按照数位dp的思想来做,每次考虑在当前这个数的二进制位和
但是数位dp毕竟难写难调,我们可以继续考虑,有一棵
#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define N 70#define LL long longLL n,m,K,P,ans,mi[N];inline int in(){ int x=0; char ch=getchar(); bool f=1; while (ch<'0'||ch>'9'){ if (ch=='-') f=0; ch=getchar(); }while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); if (!f) x=-x; return x;}inline LL Lin(){ LL x=0; char ch=getchar(); bool f=1; while (ch<'0'||ch>'9'){ if (ch=='-') f=0; ch=getchar(); }while (ch>='0'&&ch<='9') x=x*10ll+(LL)(ch-'0'),ch=getchar(); if (!f) x=-x; return x;}inline LL calc(LL x,LL y){ LL s=(((x+y)%(P*2ll))*((y-x+1)%(P*2ll)))%(P*2ll); s/=2ll,s%=P; return s;}inline LL work(LL x,LL y,int xx,int yy){ LL s=0,z; if (xx<yy) swap(x,y),swap(xx,yy); x^=(x&(mi[xx]-1)),y^=(y&(mi[xx]-1)),z=x^y; if (z>K) s=calc(z-K,z+mi[xx]-K-1); else if ((z+mi[xx])>K) s=calc(0,z+mi[xx]-K-1); s=(s*(mi[yy]%P))%P; return s;}int main(){ int T=in(),i,j,tt; LL x,y; mi[0]=1ll; for (i=1; i<=62; i++) mi[i]=mi[i-1]<<1; for (tt=1; tt<=T; tt++){ n=Lin(),m=Lin(),K=Lin(); P=Lin(),x=0ll,ans=0ll; for (i=62; i>=0; i--){ if (n&mi[i]){ y=0ll; for (j=62; j>=0; j--){ if (m&mi[j]){ ans=(ans+work(x,y,i,j))%P,y|=mi[j]; } }x|=mi[i]; } }printf("%I64d\n",ans); }return 0;}
题目大意:
给出n个数,对于两个数
题解:
最大费用最大流。题目中给出的是一个二分图,对其建网络流图:
每个奇数个质因子的数
每个偶数个质因子的数
然后跑最大费用流,直到某次增广后总费用为负,计算一下最后跑的流量即可。
#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define N 610#define M 600010#define P 2000000#define inf 1000000000#define limit -100000000000000ll#define LL long longstruct A{ int x,y,k; LL z;}a[N];struct e{ int u,v,cap,next; LL cost;}e[M*2];int n,ans=0,num=1,S,T,head[N],pre[N],flow[N],q[M*4];bool vis[N]; LL dis[N],sum=0;inline int in(){ int x=0; char ch=getchar(); bool f=1; while (ch<'0'||ch>'9'){ if (ch=='-') f=0; ch=getchar(); }while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); if (!f) x=-x; return x;}inline LL Lin(){ LL x=0; char ch=getchar(); bool f=1; while (ch<'0'||ch>'9'){ if (ch=='-') f=0; ch=getchar(); }while (ch>='0'&&ch<='9') x=x*10ll+(LL)(ch-'0'),ch=getchar(); if (!f) x=-x; return x;}inline void add(int u,int v,int cap,LL cost){ e[++num].u=u,e[num].v=v,e[num].cap=cap; e[num].cost=cost,e[num].next=head[u],head[u]=num; e[++num].u=v,e[num].v=u,e[num].cap=0; e[num].cost=-cost,e[num].next=head[v],head[v]=num;}inline void divide(int xu){ int i,x=a[xu].x,y; a[xu].k=0,y=sqrt(x); for (i=2; i<=sqrt(x); i++){ while (!(x%i)) x/=i,a[xu].k++; }if (x>1) a[xu].k++;}inline bool spfa(){ int i,u,v,h=0,t=1; for (i=S; i<=T; i++) vis[i]=0,dis[i]=limit; LL minn=dis[0]; q[h]=S,dis[S]=0ll,flow[S]=inf,vis[S]=1; while (h<t){ u=q[h%P],h++,vis[u]=0; for (i=head[u]; i; i=e[i].next){ v=e[i].v; if (e[i].cap>0&&dis[v]<dis[u]+e[i].cost){ dis[v]=dis[u]+e[i].cost,pre[v]=i; flow[v]=min(flow[u],e[i].cap); if (!vis[v]) q[t%P]=v,t++,vis[v]=1; } } }if (dis[T]>minn) return true; else return false;}int main(){ int i,j; n=in(),S=0,T=n+1; for (i=1; i<=n; i++) a[i].x=in(); for (i=1; i<=n; i++) a[i].y=in(); for (i=1; i<=n; i++) a[i].z=Lin(); for (i=1; i<=n; i++){ divide(i); if (a[i].k&1) add(S,i,a[i].y,0); else add(i,T,a[i].y,0); }for (i=1; i<=n; i++){ if (a[i].k&1){ for (j=1; j<=n; j++){ if (i==j) continue; if (!(a[j].k&1)){ if (!(a[i].x%a[j].x)&&a[i].k==a[j].k+1) add(i,j,inf,a[i].z*a[j].z); if (!(a[j].x%a[i].x)&&a[j].k==a[i].k+1) add(i,j,inf,a[i].z*a[j].z); } } } }while (spfa()){ if ((sum+dis[T]*flow[T])<0){ ans+=(int)(sum/(-dis[T])); break; }else { for (i=T; i!=S; i=e[pre[i]].u){ e[pre[i]].cap-=flow[T]; e[pre[i]^1].cap+=flow[T]; }ans+=flow[T],sum+=dis[T]*flow[T]; } }printf("%d\n",ans); return 0;}
题目大意:
给出一棵n个节点的树,每次操作选一条链,用一个自变量是和出发点的距离的一次函数更新最小值,多次询问某条链的最小值。
题解:
据说这个题是李超树,国家集训队作业题挂到了树上(听说
用线段树维护覆盖当前区间的线段,更新的时候分情况讨论,如果可以更新就下传当前线段,然后标记新线段,每次线段最多被分成
#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define N 100010#define inf 123456789123456789ll#define LL long long#define root 1,1,n#define lch rt<<1,l,mid#define rch rt<<1|1,mid+1,rstruct E{ int v,next; LL k;}e[N<<1];struct Line{ LL k,b; inline LL F(LL x){ return k*x+b; }};struct Tr{ Line x; LL minn; bool f;}tr[N<<2];int n,m,num=0,tot=0,head[N],cur[N],fa[N][20],de[N],w[N],top[N],sz[N],son[N],q[N]; LL ans,dis[N],Dis[N];inline int in(){ int x=0; char ch=getchar(); bool f=1; while (ch<'0'||ch>'9'){ if (ch=='-') f=0; ch=getchar(); }while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); if (!f) x=-x; return x;}inline LL Lin(){ LL x=0ll; char ch=getchar(); bool f=1; while (ch<'0'||ch>'9'){ if (ch=='-') f=0; ch=getchar(); }while (ch>='0'&&ch<='9') x=x*10ll+(LL)(ch-'0'),ch=getchar(); if (!f) x=-x; return x;}inline void add(int u,int v,LL k){ e[++num].v=v,e[num].k=k; e[num].next=head[u],head[u]=num;}inline void BFS(){ int i,j,u,v,h=0,t=1; q[h]=1,dis[1]=0; for (i=1; i<=n; i++) cur[i]=head[i]; while (h<t){ u=q[h++]; for (i=1; (1<<i)<=de[u]; i++) fa[u][i]=fa[fa[u][i-1]][i-1]; for (i=head[u]; i; i=e[i].next){ v=e[i].v; if (v==fa[u][0]) continue; fa[v][0]=u,de[v]=de[u]+1; dis[v]=dis[u]+e[i].k,q[t++]=v; } }for (i=t-1; i>=0; i--){ u=q[i],sz[u]=1,son[u]=0; for (j=head[u]; j; j=e[j].next){ v=e[j].v; if (v==fa[u][0]) continue; sz[u]+=sz[v]; if (sz[son[u]]<sz[v]) son[u]=v; } }for (i=0; i<t; i++){ u=q[i]; if (!w[u]){ for (j=u; j; j=son[j]) w[j]=++tot,Dis[tot]=dis[j],top[j]=u; } }}inline int lca(int x,int y){ if (de[x]<de[y]) swap(x,y); int i,k=de[x]-de[y]; for (i=18; i>=0; i--) if (k&(1<<i)) x=fa[x][i]; if (x==y) return x; for (i=18; i>=0; i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; if (x==y) return x; return fa[x][0];}inline void push_up(int rt){ tr[rt].minn=min(tr[rt].minn,min(tr[rt<<1].minn,tr[rt<<1|1].minn));}inline void build(int rt,int l,int r){ tr[rt].minn=inf,tr[rt].f=0; if (l==r) return; int mid=(l+r)>>1; build(lch),build(rch); push_up(rt);}inline void change(int rt,int l,int r,int ll,int rr,Line x){ if (ll<=l&&r<=rr){ tr[rt].minn=min(tr[rt].minn,min(x.F(Dis[l]),x.F(Dis[r]))); if (!tr[rt].f){ tr[rt].f=1,tr[rt].x=x; return; }if (l==r){ if (x.F(Dis[l])<tr[rt].x.F(Dis[l])) tr[rt].x=x; return; }int mid=(l+r)>>1; LL k1=x.F(Dis[l]),k2=tr[rt].x.F(Dis[l]); LL kk1=x.F(Dis[mid]),kk2=tr[rt].x.F(Dis[mid]); LL kkk1=x.F(Dis[r]),kkk2=tr[rt].x.F(Dis[r]); if (k1>k2&&kkk1>kkk2) return; if (k1<k2&&kkk1<kkk2){ tr[rt].x=x; return; }if (kk1<kk2) swap(x,tr[rt].x),swap(k1,k2),swap(kkk1,kkk2); if (k1<k2) change(lch,ll,rr,x); if (kkk1<kkk2) change(rch,ll,rr,x); return; }int mid=(l+r)>>1; if (ll<=mid) change(lch,ll,rr,x); if (rr>mid) change(rch,ll,rr,x); push_up(rt);}inline LL query(int rt,int l,int r,int ll,int rr){ if (ll<=l&&r<=rr) return tr[rt].minn; int mid=(l+r)>>1; LL k=inf; if (tr[rt].f) k=min(k,min(tr[rt].x.F(Dis[max(ll,l)]),tr[rt].x.F(Dis[min(rr,r)]))); if (ll<=mid) k=min(k,query(lch,ll,rr)); if (rr>mid) k=min(k,query(rch,ll,rr)); return k;}inline void work_change(int x,int y,LL z,LL zz){ int f=lca(x,y); LL k1,b1,k2,b2; k1=-z,b1=z*dis[x]+zz; k2=z,b2=z*(-2*dis[f]+dis[x])+zz; while (de[top[x]]>de[f]){ change(root,w[top[x]],w[x],(Line){k1,b1}); x=fa[top[x]][0]; }while (de[top[y]]>de[f]){ change(root,w[top[y]],w[y],(Line){k2,b2}); y=fa[top[y]][0]; }if (x!=f) change(root,w[f],w[x],(Line){k1,b1}); else if (y!=f) change(root,w[f],w[y],(Line){k2,b2}); else change(root,w[f],w[f],(Line){k1,b1});}inline void work_query(int x,int y){ ans=inf; while (top[x]!=top[y]){ if (de[top[x]]<de[top[y]]) swap(x,y); ans=min(ans,query(root,w[top[x]],w[x])); x=fa[top[x]][0]; }if (de[x]<de[y]) swap(x,y); ans=min(ans,query(root,w[y],w[x])); printf("%lld\n",ans);}int main(){ n=in(),m=in(); int i,op,x,y; LL z,zz; for (i=1; i<n; i++){ x=in(),y=in(),z=Lin(); add(x,y,z),add(y,x,z); }BFS(),build(root); for (i=1; i<=m; i++){ op=in(); if (op==1){ x=in(),y=in(),z=Lin(),zz=Lin(); work_change(x,y,z,zz); }else { x=in(),y=in(); work_query(x,y); } }return 0;}
题目大意:
开始有一个空串,n次操作,每次在串的最后新添一个字符,每次操作完后求此时串中不同字串的个数。
题解:
#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define N 200010#define LL long longint n,m,tot,a[N],sa[N],rank[N],cc[N],h[N],tt[N],height[N<<2],tr[N<<2]; LL ans=0;inline int in(){ int x=0; char ch=getchar(); bool f=1; while (ch<'0'||ch>'9'){ if (ch=='-') f=0; ch=getchar(); }while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); if (!f) x=-x; return x;}inline bool cmp(int x,int y){ return a[x]<a[y];}inline void SA(){ int i,j; for (i=1; i<=n; i++) sa[i]=i; sort(sa+1,sa+n+1,cmp); for (i=1,m=0; i<=n; i++){ m++,rank[sa[i]]=m; while (i<n&&a[sa[i]]==a[sa[i+1]]) i++,rank[sa[i]]=m; }for (j=1; j<=n&&m<n; j<<=1){ for (i=0; i<=m; i++) cc[i]=0; for (i=1; i<=n; i++) cc[rank[i+j]]++; for (i=1; i<=m; i++) cc[i]+=cc[i-1]; for (i=1; i<=n; i++) tt[cc[rank[i+j]]--]=i; for (i=0; i<=m; i++) cc[i]=0; for (i=1; i<=n; i++) cc[rank[i]]++; for (i=1; i<=m; i++) cc[i]+=cc[i-1]; for (i=n; i>=1; i--) sa[cc[rank[tt[i]]]--]=tt[i]; for (i=1,m=0; i<=n; i++){ m++,tt[sa[i]]=m; while (i<n&&rank[sa[i]]==rank[sa[i+1]]&&rank[sa[i]+j]==rank[sa[i+1]+j]) i++,tt[sa[i]]=m; }for (i=1; i<=n; i++) rank[i]=tt[i]; }for (tot=1; tot<n+5; tot<<=1); for (i=1; i<=n; i++){ if (rank[i]==1) continue; h[i]=max(0,h[i-1]-1),j=sa[rank[i]-1]; while (a[i+h[i]]==a[j+h[i]]) h[i]++; }for (i=1; i<=n; i++) height[rank[i]+tot]=h[i]; for (i=tot-1; i>=1; i--) height[i]=min(height[i<<1],height[i<<1|1]);}inline void add(int x){ for (x=x+tot; x; x>>=1) tr[x]=1;}inline int Last(int x){ for (x=x+tot; x; x>>=1) if ((x&1)&&tr[x^1]) break; for (x=x^1; x<tot;){ x<<=1; if (tr[x|1]) x|=1; }return x-tot;}inline int Next(int x){ for (x=x+tot; x; x>>=1) if ((!(x&1))&&tr[x^1]) break; for (x=x^1; x<tot;){ x<<=1; if (!tr[x]) x|=1; }return x-tot;}inline int query(int l,int r){ int s=n; l+=tot,r+=tot+1; for (; l^r^1; l>>=1,r>>=1){ if (!(l&1)) s=min(s,height[l^1]); if (r&1) s=min(s,height[r^1]); }return s;}int main(){ n=in(); int i,x,l,r; for (i=n; i>=1; i--) a[i]=in(); SA(),add(0),add(n+1); for (i=n; i>=1; i--){ ans+=(LL)(n-i+1),x=rank[i]; l=Last(x),r=Next(x),add(x); if (1<=l&&r<=n) ans+=(LL)query(l,r); if (1<=l) ans-=(LL)query(l,x); if (r<=n) ans-=(LL)query(x,r); printf("%I64d\n",ans); }return 0;}
题目大意:
求长度为n的排列中恰好有
题解:
考虑
#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define N 1000000#define P 1000000007ll#define LL long longint n,m; LL fac[N+10],inv[N+10],f[N+10];inline int in(){ int x=0; char ch=getchar(); bool f=1; while (ch<'0'||ch>'9'){ if (ch=='-') f=0; ch=getchar(); }while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); if (!f) x=-x; return x;}inline LL C(int x,int y){ return (((fac[x]*inv[y])%P)*inv[x-y])%P;}inline LL qp(LL x,LL y){ LL z=1; while (y){ if (y&1) z=(z*x)%P; x=(x*x)%P,y>>=1; }return z;}int main(){ int T=in(),tt,i; fac[0]=1ll,f[0]=1,f[1]=0,f[2]=1; for (i=1; i<=N; i++) fac[i]=fac[i-1]*(LL)i%P; inv[N]=qp(fac[N],P-2); for (i=N-1; i>=0; i--) inv[i]=inv[i+1]*(LL)(i+1)%P; for (i=3; i<=N; i++) f[i]=(LL)(i-1)*(f[i-1]+f[i-2])%P; for (tt=1; tt<=T; tt++){ n=in(),m=in(); printf("%I64d\n",C(n,m)*f[n-m]%P); }return 0;}
题目大意:
给出
题解:
令
就是求最小平方和,直接搞斜率优化就好了。
#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define N 3010#define LL long longstruct Q{ LL x,y;}q[N<<1];int n,m,a[N],s[N]; LL f[N][N],ans;inline int in(){ int x=0; char ch=getchar(); bool f=1; while (ch<'0'||ch>'9'){ if (ch=='-') f=0; ch=getchar(); }while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); if (!f) x=-x; return x;}inline void dp(int xu){ int i,h=1,t=1; LL x,y,x1,y1,x2,y2; q[h].x=(LL)s[xu-1]*2; q[h].y=f[xu-1][xu-1]+(LL)s[xu-1]*s[xu-1]; for (i=xu; i<=n; i++){ while (h<t){ x=q[h].y-q[h].x*(LL)s[i]; y=q[h+1].y-q[h+1].x*(LL)s[i]; if (x>=y) h++; else break; }f[xu][i]=q[h].y-q[h].x*(LL)s[i]+(LL)s[i]*(LL)s[i]; x=(LL)s[i]*2,y=f[xu-1][i]+(LL)s[i]*(LL)s[i]; while (h<t){ x1=x-q[t-1].x,y1=y-q[t-1].y; x2=q[t].x-q[t-1].x,y2=q[t].y-q[t-1].y; if (x2*y1-x1*y2<=0) t--; else break; }t++,q[t].x=x,q[t].y=y; }}int main(){ n=in(),m=in(); int i; for (i=1; i<=n; i++) a[i]=in(),s[i]=s[i-1]+a[i]; for (i=1; i<=n; i++) f[1][i]=(LL)s[i]*(LL)s[i]; for (i=2; i<=m; i++) dp(i); ans=f[m][n]*(LL)m-(LL)s[n]*(LL)s[n]; printf("%I64d\n",ans); return 0;}
- SDOI2016 Round 1解题报告
- [SDOI2016]sequence 解题报告
- DOJ Round #1 解题报告
- BestCoder Round #1 解题报告
- SDOI2016 Round 1游记
- Codeforces Round #250 (Div.1) 解题报告
- Codeforces Round #327 (Div. 1) 解题报告
- Codeforces Round #326 (Div. 1) 解题报告
- Codeforces Round #325 (Div. 1) 解题报告
- Round #374解题报告
- #Round 375解题报告
- SDOI2016 R1 day2 解题报告(bzoj4516,bzoj4517,bzoj4518)
- CodeForces Round#35解题报告
- PKU Round 3解题报告
- Codeforces Round #277.5 解题报告
- BestCoder Round #55 解题报告
- Codeforces-Round #340 解题报告
- 【解题报告】BestCoder Round #75
- YTUOJ之判断是否是子串(串)
- 创建IOS的alert界面
- ACM内部函数--数学问题--任意进制转换
- STM32系列第21篇--DMA
- HDU 3068:最长回文【回文字符串】
- SDOI2016 Round 1解题报告
- 第7周-项目2-友元类
- myeclipse编码问题
- nyoj 1091 还是01背包
- ios修改导航栏的title的文字颜色
- unity图片打成图集后图片变模糊
- 一个简单的http服务器的实现 含源代码
- Tyvj_P1007
- 字符串全排列