@LittleRewriter
2017-10-08T02:20:19.000000Z
字数 6904
阅读 799
60分:打表
100分:
如果强行假定a<=b<=c,那么这一答案就是这样的。
由于,可以大量减少枚举次数。
而
由于,所以,直接加上即可
for(int a=1;a*a*a<=n;++a)for(int b=a;b*b<=n/a;++b)ans+=n/a/b-b;
复杂度
问题是如果一样,那么:
三个数都一样,枚举一下;
两个数都一样,不妨假设b=c
从而枚举b的值,可以枚举出来
将这两种情况剪掉即可
可以用这个自适应win/linux输出longlong:
#ifdef WIN32#define LL "%I64d"#else#define LL "%lld"#endif/.../printf("LL",a);
标程:
#include<cstdio>#include<cstdlib>#include<cstring>using namespace std;long long n;#ifdef unix#define LL "%lld"#else#define LL "%I64d"#endif//64位都可以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;}
30分:
对每一个值都可以算出来加成
这是可以优先考虑贡献小的搜
提高搜到最优解的速度
100分:
由于“昨天考过的今天都不考”
所以这是一道DP题
我们需要考虑卡包和卡包的距离与玄学值和玄学值的距离(例如,影响5的只有4,5,6 3个值)
设计状态:这样的九维状态
表示1-i的所有玄学值已经考虑过之后的结果,使用了这些玄学值即每一个卡包用了多少玄学值。由于只能有最多5个所以这几个值都<=5
接下来的代表第p包卡中有无玄学值i,两维
f[30][5][5][5][5][2][2][2][2]空间复杂度300000
这里枚举来确定加成。由于最后四维状态确定了有无i,算一下就行了(并不
嗯,标程,请感受一下来自dp的恶意:
#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;}
最优策略:朝着对面走先抢
因此有三个阶段:
1)遇上
2)轮流从大到小抢子树
3)遍历子树
因此1)是一大难点,采用倍增求LCA
假设两点距离为l,若l为偶数则走l/2,否则走
一定有一个人始终向上走,一个人某一阶段以后从上往下走,算出到LCA的距离即可。
标程:
#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;}