2017.10.2北京清北综合强化班DAY2
a
【问题描述】
你是能看到第一题的 friends呢。
—— hja
世界上没有什么比卖的这 贵弹丸三还令人绝望事了,所以便么一道题。定义 𝑓(𝑥)为满足 (𝑎×𝑏)|𝑥的有序正整数对 (𝑎,𝑏)的个数。现在给定 𝑁,求 Σ𝑓(𝑖)𝑁𝑖=1
【输入格式】
一行个整数 𝑁。
【输出格式】
一行个整数代表答案 。
【样例输入】
6
【样例输出】
25
【数据范围与规定】
对于 30%的数据, 1≤𝑛≤100。
对于 60%的数据, 1≤𝑛≤1000。
对于 100%的数据, 1≤𝑛≤10^11。
题解:数论题
本以为写的O(n^3),结果过了60%的数据。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,ans; int main(){ freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++){ for(int j=1;j<=i;j++){ if(i%j==0) for(int k=1;k<=j;k++){ if(j%k==0)ans++; } } } cout<<ans<<endl; fclose(stdin); fclose(stdout); return 0; }
正解:求sigema(i=1--n)f(i),对于f(x)为满足(a*b)|x,的点对个数。x为a*b的倍数,
假设这个倍数为c,那么a*b*c=x,所以对于sigema(i=1--n)f(i)实质上是求a*b*c<=x,
的点对个数,假设a<=b<=c,那么最后只要将结果×6,因为对于 1 2 3这个三个数
的数列的全排列有6个。a^3<=a*b*c<=n,那么a<=(n开三次方),所以a从1枚举到n
开三方,b从a+1枚举到根号下n/a,tmp累计答案。对于a*a*a它的全排列只有1个
,所以枚举的a,b,c不能重复,因为a*a*b,的全排列只有3个,所以也要去重。
这个时候枚举a,求b,看b有没有落在a的区间。
![](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; }
b
【问题描述】
你是能看到第二题的 friends呢。
—— laekov
Hja和 Yjq为了 抢男主 角打了 起来 ,现在 他们 正在 一棵树 上决斗 。Hja在 A点,Yjq在 B点,Hja先发制人 开始 移动 。每次 他们 可以 沿着 一条边 移动 ,但 一旦 一条边 被对方 走过了 自己 就不能 再走这条边 了。每条 边上 都有 权值 ,他们 都希望 自己 的权值 尽量多 。现在 给你 这棵树 以及 他们 俩开始 的位置 ,问 Hja能 够获得 的最大权值 。
【输入格式】
第一行 两个 整数 𝑁,𝑀,代表 树的点数 和询问 的个数 。
接下来 𝑁−1行每行 三个 整数 𝑎,𝑏,𝑐,代表 从𝑎到𝑏有一条 权值 为𝑐的边 。
接下来 𝑀行,每行 两个整数 𝐴,𝐵代表 一次 询问 。
【输出格式】
对于 每次 询问 ,输出 一个 整数 代表 答案 。
【样例输入1】
2 1
1 2 3
1 2
【样例输出1】 3
【样例输入2】
3 2
1 2 3
1
3 2 3
1 3
【样例输出2】
3
4
【数据范围与规定】
对于 30%的数据 ,1≤𝑁,𝑀≤1000。
对于另外 30%的数据 ,𝑀=1。
对于 100%的数据, 1≤𝑁,𝑀≤105,0≤𝑐≤103,1≤𝑎,𝑏,𝐴,𝐵≤𝑁。
又是菊花图卡本萌妹QWQ
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #define maxn 100005 using namespace std; int n,m,sumedge,a,b; int head[maxn],size[maxn],dad[maxn],top[maxn],deep[maxn],fu[maxn],dis[maxn]; struct Edge{ int x,y,z,nxt; Edge(int x=0,int y=0,int z=0,int nxt=0): x(x),y(y),z(z),nxt(nxt){} }edge[maxn<<1]; void add(int x,int y,int z){ edge[++sumedge]=Edge(x,y,z,head[x]); head[x]=sumedge; } void dfs(int x){ size[x]=1;deep[x]=deep[dad[x]]+1; for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(v==dad[x])continue; dad[v]=x;dis[v]=edge[i].z; dfs(v); size[x]+=size[v]; fu[x]+=fu[v]+edge[i].z; } } void dfs_(int x){ int s=0; if(!top[x])top[x]=x; for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(v!=dad[x]&&size[v]>size[s])s=v; } if(s){ top[s]=top[x]; dfs_(s); } for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(v!=dad[x]&&v!=s)dfs_(v); } } int lca(int x,int y){ for(;top[x]!=top[y];){ if(deep[top[x]]>deep[top[y]])swap(x,y); y=dad[top[y]]; } if(deep[x]<deep[y])return x; return y; } void slove(int x,int y){ int zx=lca(x,y); int lena=deep[x]-deep[zx],lenb=deep[y]-deep[zx]; if(lena<lenb){ int k=(lena+lenb)/2; for(int i=1;i<=k;i++)y=dad[y]; printf("%d\n",fu[1]-fu[y]); } if(lena>lenb){ int flag=0; int k=(lena+lenb)/2+(lena+lenb)%2; for(int i=1;i<=k;i++){ if(dad[x]!=zx)x=dad[x]; else { flag=1; printf("%d\n",fu[x]+dis[x]); } } if(flag==0) printf("%d\n",fu[x]); } if(lena==lenb){ while(dad[y]!=zx)y=dad[y]; printf("%d\n",fu[1]-fu[y]-dis[y]); } } int main(){ freopen("b.in","r",stdin); freopen("b.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z);add(y,x,z); } dfs(1);dfs_(1); for(int i=1;i<=m;i++){ scanf("%d%d",&a,&b); slove(a,b); } fclose(stdin); fclose(stdout); return 0; }
![](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; }
题解:动态规划
![](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; }
ql