• 2017.7.13 C组总结


    NO.1

    题目描述:有一个n*n的矩阵,每个点上有一个值,要求两个矩阵,在只有一个交点的情况下,两个矩阵的值相等,求有多少种方案

    思路:枚举+hash+前缀合
    这里写图片描述
    矩阵只有以上两种情况,先将**前缀和**f[i,j]求出来,f[i,j]=f[i-1,j]+f[i,j-1]-f[i-1,j-1]+a[i,j]
    那么,就可以枚举它们的交点,然后分两种情况枚举:
    ①枚举第一个矩阵的左上角和第二个矩阵的右下角
    每次枚举到第一个矩阵的和x,将这个x存进哈希表里,hash[x]++
    枚举到第二个矩阵的和y,就是ans+=hash[y]
    ②枚举第一个矩阵的右上角和第二个矩阵的左下角
    每次枚举到第一个矩阵的和x,将这个x存进哈希表里,hash[x]++
    枚举到第二个矩阵的和y,就是ans+=hash[y]

    代码:

    var a,s:array[0..100,0..100] of longint;
        b:array[-2500000..2500000] of longint;
        c:array[1..100000] of longint;
        n,i,j,k,u,x,l:longint;
        ans:qword;
    begin
            assign(input,'farmer.in');
            assign(output,'farmer.out');
            reset(input);
            rewrite(output);
            readln(n);
            fillchar(s,sizeof(s),0);
            for i:=1 to n do for j:=1 to n do begin read(a[i,j]); s[i,j]:=s[i-1,j]+s[i,j-1]-s[i-1,j-1]+a[i,j]; end;
            ans:=0;
            fillchar(b,sizeof(b),0);
            for i:=1 to n do
                    for j:=1 to n do
                    begin
                            l:=0;
                            for k:=1 to i do
                                    for u:=1 to j do
                                    begin
                                            x:=s[i,j]-s[i,u-1]-s[k-1,j]+s[k-1,u-1];
                                            inc(b[x]);
                                            inc(l);
                                            c[l]:=x;
                                    end;
                            for k:=i+1 to n do
                                    for u:=j+1 to n do
                                    begin
                                            x:=s[k,u]-s[k,j]-s[i,u]+s[i,j];
                                            inc(ans,b[x]);
                                    end;
                            for k:=1 to l do b[c[k]]:=0;
                            l:=0;
                            for k:=1 to i do
                                    for u:=j to n do
                                    begin
                                            x:=s[i,u]-s[k-1,u]-s[i,j-1]+s[k-1,j-1];
                                            inc(b[x]);
                                            inc(l);
                                            c[l]:=x;
                                    end;
                            for k:=i+1 to n do
                                    for u:=1 to j-1 do
                                    begin
                                            x:=s[k,j-1]-s[k,u-1]-s[i,j-1]+s[i,u-1];
                                            inc(ans,b[x]);
                                    end;
                            for k:=1 to l do b[c[k]]:=0;
                    end;
            writeln(ans);
            close(input);
            close(output);
    end.
    

    NO.2

    题目描述:机器人有 M 种,每种机器人能完成 K 个马种之间的语言翻译。问,利用这些机器人,能否实现 1 种群和 N 种群的马语翻译。 若可以,找到翻译过程至少需要用到多少种语言。

    思路:SPFA
    其实这就是一道最短路,但是如果直接连边就会爆掉
    那么,如何实现两边呢?
    我们可以将机器人压成一个点,那么问题就转为翻译语言1的机器看做起点,能够翻译语言n的机器看做终点,求起点到终点的最短路。
    现在还剩一个问题,就是如果做到连边。
    我们开一个数组f[x]表示“语言x下连接的第一台机器”的数组下标,再开数组value[y]与next[y],value[y]中,y就是前面所说数组下标,value[y]就是这一个下标所存的机器的编号,next[y]表示这一个机器所连接的下一个机器的数组下标,当这个机器向下没有连其他机器时,next[y]就等于0。每当有机器a能翻译语言b时,在语言b的后面添加机器a
    如果我们要枚举语言b下所有的机器,该怎么做呢?
    我们可以将语言b下的所有机器保存下来,然后分别两两连边。

    代码:

    var n,k,m,x,l,l1,i,j,u,v,i1,head,tail,ans:longint;
        g:array[1..1000,1..1000] of longint;
        f:array[1..100000] of longint;
        value,next:array[1..1000000] of longint;
        p,d,first,last,vist:array[1..1000] of integer;
        q:array[1..10000000] of longint;
    begin
            assign(input,'trans.in');
            assign(output,'trans.out');
            reset(input);
            rewrite(output);
            readln(n,k,m);
            fillchar(g,sizeof(g),0);
            fillchar(f,sizeof(f),0);
            fillchar(first,sizeof(first),0);
            fillchar(last,sizeof(last),0);
            fillchar(vist,sizeof(vist),0);
            l:=0; head:=1; tail:=0;
            for i:=1 to m do
            begin
                    for j:=1 to k do
                    begin
                            read(x);
                            inc(l);
                            value[l]:=i;
                            next[l]:=f[x];
                            f[x]:=l;
                            if x=1 then first[i]:=1;
                            if x=n then last[i]:=1;
                    end;
                    if first[i]=1 then
                    begin
                            inc(tail);
                            q[tail]:=i;
                            d[i]:=1;
                            vist[i]:=1;
                    end
                    else d[i]:=10000;
            end;
            for i:=1 to n do
            begin
                    l1:=0;
                    j:=f[i];
                    while j<>0 do
                    begin
                            v:=value[j];
                            inc(l1);
                            p[l1]:=v;
                            j:=next[j];
                    end;
                    for j:=1 to l1-1 do
                            for i1:=j+1 to l1 do
                            begin
                                    g[p[j],p[i1]]:=1;
                                    g[p[i1],p[j]]:=1;
                            end;
            end;
            while head<=tail do
            begin
                    u:=q[head];
                    inc(head);
                    vist[u]:=0;
                    for v:=1 to m do
                            if (g[u][v]=1)and(d[v]>d[u]+1) then
                            begin
                                    d[v]:=d[u]+1;
                                    if vist[v]=0 then
                                    begin
                                            vist[v]:=1;
                                            inc(tail);
                                            q[tail]:=v;
                                    end;
                            end;
            end;
            ans:=10000;
            for i:=1 to m do if (last[i]=1)and(d[i]<ans) then ans:=d[i];
            if n=1 then writeln(1)
            else if ans<10000 then writeln(ans+1)
                 else writeln(-1);
            close(input);
            close(output);
    end.

    NO.3

    题目描述:首先,所有乡镇都要求,本乡镇所有的马匹都必须参赛,或者都不参赛(若组队的马匹数量不是该镇马匹数量的约数,将无法参赛)。其次,在本乡镇,选出最佳球队,参加乡镇间联赛。
    现在,比赛组织方希望满足所有参赛乡镇的要求,并且使得决赛的马匹尽可能多,请你设计每个球队马匹的数量,使得决赛马匹数最大。注意,决赛至少有 2 个队伍晋级。

    80%思路:数学
    组队马匹数c1的枚举是必要的,那么接下来我们必须在O(1)的时间内统计出有多少数能够被c1整除,如何做到O(1)呢?只有一个办法,在枚举c1之前,将答案预处理出来,比如我们用一个数组c来保存,其中c[x]表示以x为组队马匹数时,有多少个数能够整除x。
    但是c数组该怎么计算呢?枚举x吗?
    我们可以对于每个a(i) 求出它的所有因子x,对于每个x,都执行c[x]:=c[x]+1的操作,就可以将c(x)计算出来了。
    我们在事先先打一个质数表,然后利用质数表,将a(i)进行质因数分解,再利用a(i)的质因数,算出a(i)的所有因子
    计算完c数组后,题目就很容易解决了,枚举组队马匹数c1,求一个最大的c1*c[c1] (c[c1]>1),即为所求答案。

    80%代码:

    #include<cstdio>
    #include<cmath>
    #include<iostream>
    #include<memory.h>
    using namespace std;
    bool b[2000];
    long  ans,n,l,l1,a[200000],c[2000000],d[2000],e[2000],f[2000];
    void find(int x,int y)
    {
        if (x>l1)
        {
            c[y]++;
            return;
        }
        for (int i=1;i<=f[x];i++)
        {
            find(x+1,y);
            y=y*e[x];
        }
        find(x+1,y);
    }
    int main()
    {
        freopen("polo.in","r",stdin);
        freopen("polo.out","w",stdout);
        scanf("%ld",&n);
        memset(b,true,sizeof(b));
        for (int i=1;i<=n;i++) scanf("%ld",&a[i]);
        b[1]=false;
        for (int i=2;i<=trunc(sqrt(2000)+0.00001);i++)
           if (b[i]) for (int j=2;j<=2000/i;j++) b[i*j]=false;
        l=0;
        for (int i=2;i<=2000;i++)
            if (b[i])
            {
                l++;
                d[l]=i;
            }
        memset(c,0,sizeof(c));
        for (int i=1;i<=n;i++)
        {
            l1=0;
            for (int j=1;j<=l;j++)
                if (a[i]%d[j]==0)
                {
                    l1++;
                    e[l1]=d[j];
                    f[l1]=0;
                    while (a[i]%d[j]==0)
                    {
                        a[i]=a[i]/d[j];
                        f[l1]++;
                    }
                }
            if (a[i]>1)
            {
                l1++;
                e[l1]=a[i];
                f[l1]=1;
            }
            find(1,1);
        }
        ans=2;
        for (int i=1;i<=2000000;i++) if (ans<c[i]*i&&c[i]>1) ans=c[i]*i;
        printf("%ld",ans);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    100%思路:数学+递推
    首先设f[x]表示以x为组队马匹数时,有多少个数能够整除x。
    设j为i的因数那么递推公式为:
    ①f[j]=f[j]+f[i] (如果能整除i必能整除j)
    ②f[i/j]=f[i/j]+f[i](与上同理)

    100%代码:

    #include<cstdio>
    #include<cmath>
    #include<iostream>
    using namespace std;
    int n;
    long long a[2000001],f[2000001],maxn,ans;
    void init()
    {
        maxn=0;
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            f[a[i]]++;
            if (a[i]>maxn) maxn=a[i];
        }
        if (maxn==2000000) maxn=maxn/10;
    }
    void doit()
    {
        for (int i=1;i<=maxn;i++)
        {
            if (f[i]==0) continue;
            for (int j=1;j*j<=i;j++)
            {
                if (i%j==0)
                {
                    if (i!=j) f[j]=f[j]+f[i];
                    if (j!=1&&j*j!=i) f[i/j]=f[i/j]+f[i];
                }
            }
        }   
    }
    int main()
    {
        freopen("polo.in","r",stdin);
        freopen("polo.out","w",stdout);
        init();
        doit();
        ans=0;
        for (int i=1;i<=2000000;i++) if (f[i]>1&&f[i]*i>ans) ans=f[i]*i;
        printf("%lld",ans);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    NO.4

    题目描述:给定一个长度为N的数列,求一段连续的子数列满足该子数列中的各元素的平均数大于A,输出可行方案的总数。

    思路:树状数组
    我们在读入每个元素时,将其减去A,那么问题转换为求一段连续的子数列的平均值大于1
    可以用树状数组来维护
    有两个操作:①在树状数组枚举到当前的值累加起来,这个值就是操作①对答案的贡献
    ②改变一个位置的值,对当前的后面的a[2^k]…..加1

    代码:

    var
            a,sum,tree:array[0..100000] of longint;
            b:array[0..100000,1..2] of longint;
            i,j,k,l,t,n,m:longint;
            ans:int64;
    procedure qsort(i,j:longint);
    var
            l,r,mid,mid2:longint;
    begin
            l:=i;
            r:=j;
            mid:=b[(i+j) div 2,1];
            mid2:=b[(i+j) div 2,2];
            repeat
            while (b[i,1]<mid)or(b[i,1]=mid)and(b[i,2]>mid2) do inc(i);
            while (b[j,1]>mid)or(b[j,1]=mid)and(b[j,2]<mid2) do dec(j);
            if i<=j then
            begin
                    b[0]:=b[i];
                    b[i]:=b[j];
                    b[j]:=b[0];
                    inc(i);
                    dec(j);
            end;
            until i>j;
            if i<r then qsort(i,r);
            if l<j then qsort(l,j);
    end;
    function lowbit(x:longint):longint;
    begin
            exit(x and -x);
    end;
    function get(x:longint):longint;
    begin
            get:=0;
            while x>0 do
            begin
                    get:=get+tree[x];
                    x:=x-lowbit(x);
            end;
    end;
    procedure change(x,y:longint);
    begin
            while x<=n do
            begin
                    tree[x]:=tree[x]+y;
                    x:=x+lowbit(x);
            end;
    end;
    begin
            assign(input,'sequence.in');
            reset(input);
            assign(output,'sequence.out');
            rewrite(output); 
            readln(n,m);
            for i:=1 to n do
            begin
                    read(a[i]);
                    a[i]:=a[i]-m;
                    sum[i]:=sum[i-1]+a[i];
                    b[i,1]:=sum[i];
                    b[i,2]:=i;
            end;
            qsort(1,n);
            for i:=1 to n do
            begin
                    ans:=ans+get(b[i,2]-1);
                    if b[i,1]>0 then inc(ans);
                    change(b[i,2],1);
            end;
            writeln(ans);
    end.
  • 相关阅读:
    TS 3.1
    TS 3.1
    MDN 教程
    MDN 教程
    MDN 教程
    MDN 教程
    MDN 教程
    MDN 教程
    cookie会话技术
    数据库语法-1
  • 原文地址:https://www.cnblogs.com/Comfortable/p/8412267.html
Copyright © 2020-2023  润新知