noip2014Day2解题报告

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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分,这是不应该的,第一题失分说明自己对第一题的重视不够,太大意了,下次要记住教训。

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

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

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

以上是关于noip2014Day2解题报告的主要内容,如果未能解决你的问题,请参考以下文章

Noip2015day2解题报告

NOIp2016 Day1&Day2 解题报告

noip2011提高组day1+day2解题报告

NOIP2016普及组复赛解题报告

noip2014解方程解题报告

Noip2014day1解题报告