2017.10.2 QBXT 模拟赛
T1
我们所要求得是(a*b)|x 也就是 使(a*b)的倍数小于x的个数之和 1<=x<=n 我们可以 找一个c使得 (a*b*c)<=x 由于我们所求的是一个三元有序对 即 (1,2,3) 与 (1,3,2) 是两种不同的方案数 所以 我们可以强制规定 a<b<c 最坏的情况是(a*a*a)==x 所以我们就可以确定a的枚举范围 就是n开三次根号 同理 b最大枚举到 sqrt(n/a) n/(a*b) 即为 c 由于c>b>a 所以 我们枚举的c是大于b的 c的实际个数为 n(a*b)-b 每一个三元有序对一共有六种变换方式 最后*6加进ans 还有一种情况是 a,b,c 中有两个数相等 例如 a==b>c 我们只需要枚举 c==n/(a*a) 的个数 每一个三元有序对 可以有三种变换 枚举的c的个数最后*3 加进ans 最后一种情况就是 a==b==c 对ans的贡献为 1 简单判断一下就好了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstdlib> #include<cstring> using namespace std; long long n; #ifdef unix #define LL "%lld" #else #define LL "%I64d" #endif int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf(LL,&n); long long ans=0,tmp=0; for (long long a=1,v;a*a<=(v=n/a);a++,ans++) for (long long b=a+1;b*b<=v;b++) tmp+=n/(a*b)-b; ans+=tmp*6; tmp=0; for (long long a=1,v;(v=a*a)<=n;a++) { tmp+=n/v; if (a*a<=n/a) tmp--; } ans+=tmp*3; printf(LL "\n",ans); return 0; }
T2
倍增LCA 巧妙地搞一搞 对于两个人 想要最大的权值 一定要先把对方给封锁 就是 让对方走过的点越少越好 所以 两个人 一定是先对着走 树上任意两个点之间的路径是唯一的 所以两个人碰面的点 也是一定的 即为 两个人之间点数的中位数 这个点用LCA 求出 求出之后 这个点还可能连着多条边 对于先手会先选一颗权值最大的子树 先走一条边 后手会选次大的子树 走一条边 两者退回继续选取要走的子树 直到走不动了 最后ans再加上已经占领的子树的权值 即为最大权值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; const int maxn=100010; int n,m,en,z[maxn*3],f[maxn][20],q[maxn],depth[maxn],sum[maxn*3][2],fd[maxn],start[maxn],end[maxn],value[maxn]; struct edge { int e,d; edge *next; }*v[maxn],ed[maxn<<1]; void add_edge(int s,int e,int d) { en++; ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->d=d; } int get(int p,int d) { if (d==-1) return p; int x=0; while (d) { if (d&1) p=f[p][x]; d>>=1; x++; } return p; } int get_lca(int p1,int p2) { if (depth[p1]<depth[p2]) swap(p1,p2); p1=get(p1,depth[p1]-depth[p2]); int x=0; while (p1!=p2) { if (!x || f[p1][x]!=f[p2][x]) { p1=f[p1][x]; p2=f[p2][x]; x++; } else x--; } return p1; } int calc(int p1,int p2) { if (p1==f[p2][0]) return value[1]-value[p2]; else return value[p1]+fd[p1]; } int calcp(int p,int v) { int l=start[p]-1,r=end[p]; while (l+1!=r) { int m=(l+r)>>1; if (v>z[m]) l=m; else r=m; } return r; } int main() { freopen("b.in","r",stdin); freopen("b.out","w",stdout); scanf("%d%d",&n,&m); int tot=0; for (int a=1;a<n;a++) { int s,e,d; scanf("%d%d%d",&s,&e,&d); tot+=d; add_edge(s,e,d); add_edge(e,s,d); } depth[1]=1; int front=1,tail=1; q[1]=1; for (;front<=tail;) { int now=q[front++]; for (edge *e=v[now];e;e=e->next) if (!depth[e->e]) { depth[e->e]=depth[now]+1; fd[e->e]=e->d; f[e->e][0]=now; int p=now,x=0; while (f[p][x]) { f[e->e][x+1]=f[p][x]; p=f[p][x]; x++; } q[++tail]=e->e; } } int cnt=0; for (int a=n;a>=1;a--) { int now=q[a]; start[now]=cnt+1; for (edge *e=v[now];e;e=e->next) if (depth[e->e]==depth[now]+1) { z[++cnt]=value[e->e]+e->d; value[now]+=value[e->e]+e->d; } z[++cnt]=tot-value[now]; end[now]=cnt; sort(z+start[now],z+end[now]+1); sum[end[now]][0]=z[end[now]]; sum[end[now]][1]=0; for (int a=end[now]-1;a>=start[now];a--) { sum[a][0]=sum[a+1][0]; sum[a][1]=sum[a+1][1]; if ((a&1)==(end[now]&1)) sum[a][0]+=z[a]; else sum[a][1]+=z[a]; } cnt++; } for (int a=1;a<=m;a++) { int p1,p2; scanf("%d%d",&p1,&p2); int lca=get_lca(p1,p2); int dist=depth[p1]+depth[p2]-2*depth[lca]; int delta=dist/2+(dist&1); int px,px1,px2; if (depth[p1]-depth[lca]<delta) px=get(p2,dist-delta); else px=get(p1,delta); if (depth[p1]-depth[lca]<delta-1) px1=get(p2,dist-delta+1); else px1=get(p1,delta-1); if (depth[p2]-depth[lca]<dist-delta-1) px2=get(p1,delta+1); else px2=get(p2,dist-delta-1); int ans=0; if (p1==px) { if (p2==px) ans=sum[start[px]][0]; else { int v2=calc(px2,px); int p=calcp(px,v2); ans=sum[p+1][0]+sum[start[px]][1]-sum[p][1]; } } else { if (p2==px) { int v1=calc(px1,px); int p=calcp(px,v1); ans=v1+sum[p+1][1]+sum[start[px]][0]-sum[p][0]; } else { int v1=calc(px1,px); int pp1=calcp(px,v1); int v2=calc(px2,px); int pp2=calcp(px,v2); if (pp2==pp1) pp2++; if (pp1>pp2) swap(pp1,pp2); ans=v1+sum[pp2+1][dist&1]+sum[pp1+1][1-(dist&1)]-sum[pp2][1-(dist&1)]+sum[start[px]][dist&1]-sum[pp1][dist&1]; } } printf("%d\n",ans); } return 0; }
T3
怀疑人生的搜索加9维DP
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define now pre[a][b][c][d][e][s1][s2][s3][s4] #define dis(a,b,c,d) (abs(a-c)+abs(b-d)) const int INF=0x3f3f3f3f; int A,B,C,D,E,num[10][10],value[10][10][10],delta[10][10][40],dp[31][6][6][6][6][2][2][2][2]; char s[500]; bool map[6][6][6][6]; int main() { freopen("c.in","r",stdin); freopen("c.out","w",stdout); scanf("%d%d%d%d%d",&A,&B,&C,&D,&E); for (int a=0;a<6;a++) { scanf("%s",s); int p=0; for (int b=0;b<6;b++) { int px=p; while (s[px]!=']') px++; p++; num[a][b]=s[p]-'0'; p++; p++; for (int c=1;c<=num[a][b];c++) { int v=0; while (s[p]>='0' && s[p]<='9') { v=v*10+s[p]-'0'; p++; } value[a][b][c]=v; p++; } p=px+1; } } int base=0; for (int a=0;a<6;a++) for (int b=0;b<6;b++) if (a>=2 && a<=3 && b>=2 && b<=3) ; else { sort(value[a][b]+1,value[a][b]+num[a][b]+1); for (int c=2;c<=num[a][b];c++) if (value[a][b][c]-value[a][b][c-1]==1) base+=A; for (int c=2;c<=3;c++) for (int d=2;d<=3;d++) { if (dis(a,b,c,d)==1) { for (int e=1;e<=num[a][b];e++) { delta[c][d][value[a][b][e]]+=B; delta[c][d][value[a][b][e]-1]+=C; delta[c][d][value[a][b][e]+1]+=C; } } if (dis(a,b,c,d)==2) { for (int e=1;e<=num[a][b];e++) { delta[c][d][value[a][b][e]]+=D; delta[c][d][value[a][b][e]-1]+=E; delta[c][d][value[a][b][e]+1]+=E; } } } for (int c=0;c<6;c++) for (int d=0;d<6;d++) if (dis(a,b,c,d)<=2 && (c!=a || d!=b) && !map[a][b][c][d]) { map[a][b][c][d]=map[c][d][a][b]=true; if (c>=2 && c<=3 && d>=2 && d<=3) ; else { int dist=dis(a,b,c,d); for (int e=1;e<=num[a][b];e++) for (int f=1;f<=num[c][d];f++) { if (abs(value[a][b][e]-value[c][d][f])==0) { if (dist==1) base+=B; else base+=D; } if (abs(value[a][b][e]-value[c][d][f])==1) { if (dist==1) base+=C; else base+=E; } } } } } memset(dp,0x3f,sizeof(dp)); dp[0][0][0][0][0][0][0][0][0]=base; for (int a=0;a<30;a++) for (int b=0;b<=num[2][2];b++) for (int c=0;c<=num[2][3];c++) for (int d=0;d<=num[3][2];d++) for (int e=0;e<=num[3][3];e++) for (int s1=0;s1<=1;s1++) for (int s2=0;s2<=1;s2++) for (int s3=0;s3<=1;s3++) for (int s4=0;s4<=1;s4++) if (dp[a][b][c][d][e][s1][s2][s3][s4]!=INF) { int v=dp[a][b][c][d][e][s1][s2][s3][s4]; for (int sx1=0;sx1<=(b!=num[2][2]);sx1++) for (int sx2=0;sx2<=(c!=num[2][3]);sx2++) for (int sx3=0;sx3<=(d!=num[3][2]);sx3++) for (int sx4=0;sx4<=(e!=num[3][3]);sx4++) { int wmt=0; if (sx1) { wmt+=delta[2][2][a+1]; if (s1) wmt+=A; if (s2) wmt+=C; if (s3) wmt+=C; if (s4) wmt+=E; } if (sx2) { wmt+=delta[2][3][a+1]; if (s1) wmt+=C; if (s2) wmt+=A; if (s3) wmt+=E; if (s4) wmt+=C; } if (sx3) { wmt+=delta[3][2][a+1]; if (s1) wmt+=C; if (s2) wmt+=E; if (s3) wmt+=A; if (s4) wmt+=C; } if (sx4) { wmt+=delta[3][3][a+1]; if (s1) wmt+=E; if (s2) wmt+=C; if (s3) wmt+=C; if (s4) wmt+=A; } if (sx1 && sx2) wmt+=B; if (sx1 && sx3) wmt+=B; if (sx1 && sx4) wmt+=D; if (sx2 && sx3) wmt+=D; if (sx2 && sx4) wmt+=B; if (sx3 && sx4) wmt+=B; int &t=dp[a+1][b+sx1][c+sx2][d+sx3][e+sx4][sx1][sx2][sx3][sx4]; if (t>v+wmt) t=v+wmt; } } int ans=INF; for (int a=0;a<=1;a++) for (int b=0;b<=1;b++) for (int c=0;c<=1;c++) for (int d=0;d<=1;d++) ans=min(ans,dp[30][num[2][2]][num[2][3]][num[3][2]][num[3][3]][a][b][c][d]); printf("%d\n",ans); return 0; }
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。