NOIP2014 Day2

来源:互联网 发布:职场女强人知乎 编辑:程序博客网 时间:2024/06/07 16:53

T1 无线网络发射器选址

模拟大水题
可以用前缀和优化
O(128128)

#include<bits/stdc++.h>using namespace std;#define M 130int a[M][M];int main(){    int d,n,i,j,ans=0,cnt=0;    scanf("%d%d",&d,&n);    for (i=1;i<=n;i++){        int x,y,z;        scanf("%d%d%d",&x,&y,&z);        x++,y++;        a[x][y]+=z;    }    for (i=1;i<M;i++)        for (j=1;j<M;j++)            a[i][j]=a[i][j]+a[i-1][j]+a[i][j-1]-a[i-1][j-1];    for (i=1;i<M;i++)        for (j=1;j<M;j++){            int l1=max(i-d-1,0),r1=min(i+d,M-1);            int l2=max(j-d-1,0),r2=min(j+d,M-1);            int sum=a[r1][r2]-a[l1][r2]-a[r1][l2]+a[l1][l2];            if (ans<sum) ans=sum,cnt=1;            else if (ans==sum) cnt++;        }    printf("%d %d\n",cnt,ans);    return 0;}

T2 寻找道路

首先可以把满足条件的点都找出来
建反向边 从终点开始bfs一遍 标记
然后可以对于每个点判断他周围的点是否标记过
最后用找出来满足的点重新从起点开始bfs一遍即可
边权为1 不需要用最短路算法
O(n+m)

#include<bits/stdc++.h>using namespace std;#define N 10010#define M 200010#define INF (0x3f3f3f3f)struct edge{    int nxt,t;}e[M<<1];int head1[N],head2[N],edge_cnt;void add_edge(int x,int y){    e[edge_cnt]=(edge){head1[x],y};    head1[x]=edge_cnt++;    e[edge_cnt]=(edge){head2[y],x};    head2[y]=edge_cnt++;}int n,m,S,T;struct P1{    int dis[N];    bool vis[N],b[N];    queue<int>Q;    void bfs1(){        int i;        Q.push(T);        vis[T]=1;        while (!Q.empty()){            int x=Q.front();            Q.pop();            for (i=head2[x];~i;i=e[i].nxt){                int to=e[i].t;                if (!vis[to]){                    vis[to]=1;                    Q.push(to);                }            }        }       }    void bfs2(){        int i;        memset(dis,63,sizeof(dis));        Q.push(S);        dis[S]=0;        while (!Q.empty()){            int x=Q.front();            Q.pop();            for (i=head1[x];~i;i=e[i].nxt){                int to=e[i].t;                if (b[to] && dis[to]>dis[x]+1){                    dis[to]=dis[x]+1;                    Q.push(to);                }            }        }    }    void solve(){        int i,j;        bfs1();        for (i=1;i<=n;i++){            b[i]=1;            for (j=head1[i];~j;j=e[j].nxt){                int to=e[j].t;                if (!vis[to]){                    b[i]=0;                    break;                }            }        }        bfs2();        printf("%d\n",dis[T]==INF?-1:dis[T]);    }}P100;int main(){    memset(head1,-1,sizeof(head1));    memset(head2,-1,sizeof(head2));    int i;    scanf("%d%d",&n,&m);    for (i=1;i<=m;i++){        int x,y;        scanf("%d%d",&x,&y);        add_edge(x,y);    }    scanf("%d%d",&S,&T);    P100.solve();    return 0;}

T3 解方程

高精模拟50分 然而正解码量远小于高精
由于Ai特别大 很难计算 不妨用类似哈希的方法 把所有Ai都对一个质数取模
之后就可以用这个质数取模运算了
防止误差 可以多设几个质数
这样可以写到70分 效率不高

假设f(x)为原方程%P后的函数
那么显然f(x)f(x%P)(modP)
于是可以找若干个较小的质数 预处理出定义域内所有的函数值
枚举答案 如果%所有质数下的函数值都为0 那么就可以认为是一个整数解
O((n+m)P)

#include<bits/stdc++.h>using namespace std;#define N 110#define M 1000010int mo[5]={2333,2339,2341,2347,2351};char str[10010];int a[N][5],ans[M],sum[5][3020];void get(int p){    int len=strlen(str),i,j;    for (i=(str[0]=='-'?1:0);i<len;i++)        for (j=0;j<5;j++)            a[p][j]=(a[p][j]*10+str[i]-'0')%mo[j];}int main(){    int n,m,i,j,k,cnt=0;    scanf("%d%d",&n,&m);    for (i=0;i<=n;i++){        scanf("%s",str);        get(i);        if (str[0]=='-')            for (k=0;k<5;k++) a[i][k]=mo[k]-a[i][k];    }    for (k=0;k<5;k++)        for (i=0;i<mo[k];i++)            for (j=n;j>=0;j--)                sum[k][i]=(sum[k][i]*i+a[j][k])%mo[k];    for (i=1;i<=m;i++){        bool ok=1;        for (k=0;k<5;k++)            if (sum[k][i%mo[k]]) ok=0;        if (ok) ans[++cnt]=i;    }    printf("%d\n",cnt);    for (i=1;i<=cnt;i++) printf("%d\n",ans[i]);    return 0;}

Date:2017/10/19
By CalvinJin