• noip2014Day2解题报告


    1.无线网络发射器选址

    题目::https://www.luogu.org/problem/show?pid=2038

    题解::第一题水题,直接枚举放的位置,用二维前缀和维护一下,注意一下边界就行了。时间复杂度O(129^2);

    代码::

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    template<class T>inline void read(T &x)
    {
        x=0;int f=0;char ch=getchar();
        while(ch<'0'||ch>'9')f|=(ch=='-'),ch=getchar();
        while(ch<='9'&&ch>='0')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=f?-x:x;
        return;
    } 
    int sum[200][200],num[200][200];
    int main()
    {
        int d,n,x,y,k,t=0,ans=0;
        read(d);read(n);
        for(int i=1;i<=n;i++)
        {
            read(x);read(y);read(k);
            num[x+1][y+1]=k;
        }
        for(int i=1;i<=129;i++)
        for(int j=1;j<=129;j++)
        sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+num[i][j];
        for(int i=1;i<=129;i++)
        for(int j=1;j<=129;j++)
        {
            int x1=min(129,i+d),y1=min(129,j+d),x2=max(0,i-d-1),y2=max(0,j-d-1);
            if(sum[x1][y1]+sum[x2][y2]-sum[x1][y2]-sum[x2][y1]>ans)
            {
                ans=sum[x1][y1]+sum[x2][y2]-sum[x1][y2]-sum[x2][y1];
                t=1;
            }
            else if(sum[x1][y1]+sum[x2][y2]-sum[x1][y2]-sum[x2][y1]==ans)t++;
        }
        printf("%d %d\n",t,ans);
        return 0;
    }

    2.寻找道路

    题目::https://www.luogu.org/problem/show?pid=2296

    题解::先反向建边bfs求出所有与终点不联通的点,在枚举每个点的每条边的终点是否联通,判断出可以在路径上的点,最后跑一边最短路就可以了;

    代码::

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 10010
    #define inf 2000000010
    using namespace std;
    template<class T>inline void read(T &x)
    {
        x=0;int f=0;char ch=getchar();
        while(ch<'0'||ch>'9')f|=(ch=='-'),ch=getchar();
        while(ch<='9'&&ch>='0')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=f?-x:x;
        return;
    } 
    struct node{int v,next;}e[200100],E[200100];
    int cnt,head[maxn],Head[maxn],d[maxn],q[1000100],n,m;
    bool vis[maxn],can[maxn];
    void ins(int u,int v){e[++cnt].v=v;e[cnt].next=head[u];head[u]=cnt;}
    void Ins(int u,int v){E[cnt].v=v;E[cnt].next=Head[u];Head[u]=cnt;}
    void bfs(int s)
    {
        vis[s]=true;
        int h=0,t=0;q[0]=s;
        while(h<=t)
        {
            int u=q[h++];
            for(int p=Head[u];p;p=E[p].next)
            {
                int v=E[p].v;
                if(!vis[v])q[++t]=v,vis[v]=true;
            }
        }
    }
    void init()
    {
        memset(can,true,sizeof(can));
        for(int i=1;i<=n;i++)
        if(!vis[i])can[i]=false;
        else for(int p=head[i];p;p=e[p].next)
        {
            int v=e[p].v;
            if(!vis[v])can[i]=false;    
        }
    }
    int spfa(int s,int T)
    {
        memset(vis,false,sizeof(vis));
        memset(d,0x7f,sizeof(d));
        d[s]=0;vis[s]=true;q[0]=s;
        int h=0,t=0;
        while(h<=t)
        {
            int u=q[h++];
            for(int p=head[u];p;p=e[p].next)
            {
                int v=e[p].v;
                if(!can[v])continue;
                if(d[v]>d[u]+1)
                {
                    d[v]=d[u]+1;
                    if(!vis[v])vis[v]=true,q[++t]=v; 
                }
            }
            vis[u]=false;
        }
        if(d[T]>inf)return -1;
        else return d[T];
    }
    int main()
    {
        int x,y,s,t;
        read(n);read(m);
        for(int i=1;i<=m;i++)
        {
            read(x);read(y);ins(x,y);Ins(y,x);
        } 
        read(s);read(t);
        bfs(t);
        init();
        if(!can[s])printf("-1\n");
        else printf("%d\n",spfa(s,t));
        return 0;
    }

    3.解方程

    题目::https://www.luogu.org/problem/show?pid=2312

    题解::如果直接按照题目模拟,不仅时间复杂度上很难接受,而且要打高精度乘和高精度加,代码复杂度很大。那么我们该怎么办呢?我们可以想到如果一个数为0,那么这个数对任意一个数取余也为0,反过来却不一定,所以我们对这个数对很多的质数取余,

    如果都为0,那么这个数就是0,这些质数怎么选呢?我们选3到4个质数使他们的乘积大于m的最大值即可。这样做是O(nmk)k是质数的个数,这样是70分的。那么怎么办?

    如果有一个数x,他对一个质数p取余为y,那么x+p对p取余也为y,所以我们不需要枚举m个数,只需要枚举p-1个数(p是我们选的质数),这样就可以过了。

    tips:读入时,我们一位一位的读,同时取余,这样就不需要高精度了。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    long long a[110][6];
    char s;
    int ans[1000010],f[31010][3],cnt,n,m,mod[6]={10007,10917,30071};
    void read(int x)
    {
        long long ret=0,F=0,cnt=0;
        char ch=s;
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')F=1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            for(int i=0;i<3;i++)a[x][i]=(a[x][i]*10+ch-'0')%mod[i];
            ch=getchar();
        }
        if(F)for(int i=0;i<3;i++)a[x][i]=mod[i]-a[x][i];
    }
    bool solve(long long x,int op)
    {
        long long sum=0;
        for(int i=n;i>=0;i--)sum=(a[i][op]+sum*x)%mod[op];
        return !sum;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n;i++)read(i);
        for(int i=0;i<3;i++)
        for(int j=0;j<mod[i];j++)
            f[j][i]=solve(j,i);
        for(int i=1;i<=m;i++)
            if(f[i%mod[0]][0]&&f[i%mod[1]][1]&&f[i%mod[2]][2])ans[++cnt]=i;
        printf("%d\n",cnt);
        for(int i=1;i<=cnt;i++)printf("%d\n",ans[i]);
        return 0;
    }

    测试成绩:

    总分240

    第一题:70

    第二题:100

    第三题:70

    总结:

    第一题打二维前缀和时,边界判断错误,失掉了30分,这是不应该的,第一题失分说明自己对第一题的重视不够,太大意了,下次要记住教训。

    第二题思路比较清晰,打的也比较快,这也归功于平常的图论刷的比较多。别的类型的题刷的还是少了。

    第三题想的比较久,打的比较久,成绩也还行,差一点就想到正解了,数学题还是比较难,也没什么办法……

    这次测试总的来说做的还行,希望能继续保持下去。

  • 相关阅读:
    310. Minimum Height Trees -- 找出无向图中以哪些节点为根,树的深度最小
    297. Serialize and Deserialize Binary Tree *HARD*
    235.236. Lowest Common Ancestor of a Binary (Search) Tree -- 最近公共祖先
    222. Count Complete Tree Nodes -- 求完全二叉树节点个数
    208. Implement Trie (Prefix Tree) -- 键树
    excel函数累加求和与累计百分比应用
    js去除空格
    js获取标签下标
    js中对String去空格
    css的三种使用方式:行内样式,内嵌样式,外部引用样式
  • 原文地址:https://www.cnblogs.com/jiangtao0508/p/7719797.html
Copyright © 2020-2023  润新知