【10.30 P98】

来源:互联网 发布:贷款平台网站源码 编辑:程序博客网 时间:2024/06/05 17:51

有一种做题的感觉叫做“诶,好巧啊你也是只T1暴力是吧?”
嗯。。。烦啊。。。

T1

这里写图片描述同时给定a*b≤n(a,b不保证小于n)

【输入格式】
一行一个整数n。
【输出格式】
一行一个整数代表答案。
【样例输入】
6
【样例输出】
25
【数据范围与规定】
对于30%的数据, 1 ≤ n ≤ 100。
对于60%的数据, 1 ≤ n ≤ 1000。
对于100%的数据, 1 ≤ n ≤ 10^11

思路:

题目给定 (a*b)|x
由题意分析 设x÷ab=c
则 x=abc
N≥abc
∴ a≤b ≤c(a最小为三次根号n)

分三种情况处理:
{
a=b 1
a=c||b=c 2
a!=b!=c 6(3!)
}

先处理重复(3种)和不重复情况 (6种)
像是对于X=6来说
1 1 6 a=b
1 6 1 , 6 1 1 a=c b=c
1 2 3 , 2 1 3 , 1 3 2 , 3 1 2 , 2 3 1 , 3 2 1 a!=b!=c

#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>using namespace std;#define LL long longLL n,ans = 0,now = 0;/*    对于(a * b)| x    即 x % ab == 0      设x / ab == c        即 x == abc     设a <= b <= c        则a <= (三次根下n)^ 2 //打不出来数学符号QAQ    这样答案数为 满足 abc <= n  的方案数 */ LL read(){//不讲手读不讲手读     char ch = getchar(); LL x = 0,f = 1;    while(!('0' <= ch && ch <= '9')){if(ch == '-') f = -1; ch = getchar();}    while('0' <= ch && ch <= '9') {x = (x << 3) + (x << 1) + (ch - '0'); ch = getchar();}    return x * f;}// a * b * c == x  a != b != c ;  a = c  b = c  ; a = b = c// i * i * i <= n    i * i <= n / i//也就是 a * a * a <= n  b * b <= n / a int main(){    freopen("a.in","r",stdin);    freopen("a.out","w",stdout);        n = read();now = 0;    for(LL i = 1; (i * i) <= n; i ++){        now += n / (i * i);//a == b        LL s = n / i;        /*            i * i <= n / i    ->   i * i * i <= n            即当前a == b == c == i 合法           */        if(i * i <= s) ans ++,now --;//a==b==c相同     }//重复情况    ans += now * 3,now = 0;     for(LL i = 1; (i * i) <= (n / i); i ++){        LL s =  n / i;    //  cout << "i " << i << " s " << s << endl;        for(LL j = i + 1; (j * j) <= s; j ++)            now += n / (i * j) - j;            //a b c互不相等 //i就是a j就是b  必有j < c 所以c的取值不能包含<=j的部分     }//排列 a != b != c  3! = 6      ans += 6 * now; now = 0;     printf("%I64d\n",ans);    fclose(stdin);fclose(stdout);    return 0;}

T2

【问题描述】
Hja 和 Yjq 为了抢男主角打了起来, 现在他们正在一棵树上决斗。 Hja 在 A点, Yjq 在 B 点, Hja 先发制人开始移动。 每次他们可以沿着一条边移动, 但一旦一条边被对方走过了自己就不能再走这条边了。 每条边上都有权值, 他们都希望自己的权值尽量多。 现在给你这棵树以及他们俩开始的位置, 问 Hja 能够获得的最大权值。
【输入格式】
第一行两个整数n, m, 代表树的点数和询问的个数。
接下来n − 1行每行三个整数a,b,c, 代表从a到b有一条权值为c的边。
接下来m行, 每行两个整数A, B代表一次询问。
【输出格式】
对于每次询问, 输出一个整数代表答案。
【样例输入 1】
2 1
1 2 3
1 2
【样例输出 1】
3
【样例输入 2】
3 2
1 2 3
1 3 1
2 3
1 3
【样例输出 2】
3 4
【数据范围与规定】
对于30%的数据, 1 ≤ n, m ≤ 1000。
对于另外30%的数据, m = 1。
对于100%的数据, 1 ≤ n, m ≤ 105, 0 ≤ c ≤ 103, 1 ≤a , b, A, B ≤ n

题解

60分做法
问题是找树上最大权值和,我们可以转化为求两点之间最快相遇点(先全力向前跑争取相遇,因为一个人经过一条边后对方不能再走这条边,保证了这条边下的所有子树均不可能被对方走到,所以转化成抢占更多子树,通过更快的跑路来实现)
先染色找到相遇点
两个点如果在同一地点出发,那么A跑出来的结果是全图边权和(需要特判一下,有可能会出现这种情况)
如果到了相遇点, 以这个点为中心扫一圈, 有延伸子树则判断子树大小以及优先权
Q:那么优先权的确定?
偶数条边是两点同时相遇
奇数则探讨先手权
dis[n]/2为中间点,判断中间点在相遇点的那一侧,如果更靠近A那么A有先手权,重合就直接A走
确定子树大小,排一遍序,更大子树是归有先手权的走(保证两人都是最优的最优)
Q:如何确定子树大小
dfs确定,虽然时间复杂度会非常高导致后面的超时

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<queue>using namespace std;int ans = 0;int fst[233333], nxt[233333], sd[100050], tot = 0, dis[100050], val[100050];bool used[100050];int vis[100050];int ro[100050], fa[100050];struct qer{    int f, t, d;}es[233333];struct fw{    int dx, id;}xl[100050];queue <int> q;void build (int f, int t, int d){    es[++tot] = (qer){f, t, d};    nxt[tot] = fst[f];    fst[f] = tot;}void spfa(int s){    while (!q.empty())        q.pop();    memset(used, 0, sizeof(used));    used[s] = 1;    q.push(s);    dis[s] = 0;    while (!q.empty())    {        int u = q.front();        q.pop();        used[u] = 0;        for (int i = fst[u]; i; i = nxt[i])        {            int v = es[i].t;            if (dis[v] > dis[u] + 1)            {                dis[v] = dis[u] + 1;                ro[v] = u;                if (!used[v])                {                    used[v] = 1;                    q.push(v);                }            }        }    }}void dfs(int x){    for (int i = fst[x]; i; i = nxt[i])    {        int v = es[i].t;        if (!sd[v])        {            sd[v] = sd[x] + 1;            fa[v] = x;            dfs(v);            val[x] += val[v] + es[i].d;        }    }}bool cmp (fw a, fw b){    return a.dx > b.dx;}void deal(int x, bool xs){    int cnt = 0;    for (int i = fst[x]; i; i = nxt[i])        if (!vis[es[i].t])        {            xl[++cnt].dx = es[i].d + val[es[i].t];            xl[cnt].id = i;        }    sort(xl + 1, xl + cnt + 1, cmp);    for (int i = 1; i <= cnt; i++)    {        if (xs)            ans += xl[i].dx;        if (xs)            xs = 0;        else            xs = 1;    }    for (int i = fst[x]; i; i = nxt[i])    {        int v = es[i].t;        if (vis[v] == 2)        {            ans += es[i].d + val[v];            break;        }    }}int main(){    freopen("b.in", "r", stdin);    freopen("b.out", "w", stdout);    int n, m;    cin >> n >> m;    for (int i = 1; i < n; i++)    {        int f, t, d;        scanf("%d%d%d", &f, &t, &d);        build (f, t, d);        build (t, f, d);    }    for (int i = 1; i <= m; i++)    {        int a, b;        scanf("%d%d", &a, &b);        memset(dis, 0x3f, sizeof(dis));        memset(ro, 0, sizeof(ro));        spfa(a);        int j;        for (j = b; dis[ro[j]] >= (dis[b]+1) / 2 && j; j = ro[j]);        int col = 1;        for (int ls = b; ls; ls = ro[ls])        {            vis[ls] = col;            if (ls == j)                col = 2;        }        memset(sd, 0, sizeof(sd));        memset(val, 0, sizeof(val));        for (int k = 0; k <= n; k++)            fa[k] = k;        sd[j] = 1;        dfs(j);        bool xs = 1;        if (dis[j] > dis[b] / 2)            xs = 0;        ans = 0;        deal(j, xs);        printf("%d\n", ans);        memset(vis, 0, sizeof(vis));    }    fclose(stdin);    fclose(stdout);    return 0;}

100分的话题解给出的是“倍增lca”。emmm
代码如下ε=(´ο`*))):

#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

这里写图片描述
这里写图片描述
这里写图片描述

代码(连题解都不是了)

扔出来就是为了闪瞎眼的【微笑】
九维dp,就是我总结里说过的那个ε=(´ο`*))) ↓
http://blog.csdn.net/qq_36693514/article/details/77822162
实在是。。。无话可说,真的。。。emmmmm
代码如下(无力):

#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;}
原创粉丝点击