noip2014day2解题报告

noip2014day2


t2寻找道路
1.首先按照前向星存储边,根据%2来判断是正边还是反边。
2.从终点向起点反强调内容向bfs
3.判断每一条边的终点,若未bfs到,则将其起点设为不可访问(以为该起点不能满足所有出边直接、间接到达总终点)。
4.再重新从起点开始bfs,找到最短路径,输出。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
struct Node{
    int y,next;
}e[400005];
int u1[200005];
int u2[200005];
int tot=0;
int head[10005];
bool vis[10005];
int n,m,s,t,flag;
int d[10005];
void add(int u,int v)
{
    e[++tot].y=v;
    e[tot].next=head[u];
    head[u]=tot;
}
queue<int> q;
void bfs(int x,int flag)
{
    memset(d,-1,sizeof(d));
    q.push(x);
    d[x]=0;
    while(!q.empty())
    {
      int k=q.front();
      for(int i=head[k];i!=0;i=e[i].next)
      {
        if(vis[e[i].y]==false&&i%2==flag)
        {
          int v=e[i].y;
          if(d[v]==-1)d[v]=d[k]+1,q.push(v);
        }
      }
      q.pop();
    }
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(head,0,sizeof(head));
    int u,v;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        u1[i]=u;
        u2[i]=v;
        add(u,v);
        add(v,u);
    }
    scanf("%d%d",&s,&t);
    memset(vis,false,sizeof(vis));
    bfs(t,0);
    for(int i=1;i<=m;i++)
      if(d[u2[i]]==-1)vis[u1[i]]=true;
    vis[s]=false;
//    for(int i=1;i<=n;i++)cout<<vis[i]<<' ';cout<<endl;
    bfs(s,1);
    printf("%d\n",d[t]);
    return 0;
} 

Noip2014day2t3
思路:
看了网上的题解,总结一下。
解方程没有公式,所以只能枚举。
问题一:系数是高精度数,难道要用高精度?
答:系数很大的话,第一想法应该是取模好吗。。
如果担心取一个会不准确的话,可以选择多个。
问题二:取模后,需要枚举1~m来确定解吗?
答:当然不需要。
对于f(x)%p!=0那么显然f(x+np)%p!=0。
故我们只需要枚举1~p-1,就可以据此确定1~m范围内哪些数不可以做解。同上,我们需要多个质数,这样就基本可以确定范围内的解。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
const int prime[]={10007,10917,30071};
int n,m;
int a[110][5];
char s[20000];
bool f[30100][5];
int cnt[1000006];
bool calc(int value,int j)
{
    long long tmp=0;
    for(int i=n;i>=0;i--)
     tmp=(tmp*value+a[i][j])%prime[j];
    return tmp!=0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<=n;i++)
    {
        scanf("%s",s);
        int len=strlen(s);
        int sign=1;
        for(int l=0;l<len;l++)
        {
            if(s[l]=='-')
             sign=-1;
            else
            for(int j=0;j<3;j++)
              a[i][j]=(a[i][j]*10+s[l]-'0')%prime[j];
        }
        if(sign==-1)
          for(int j=0;j<3;j++)
            a[i][j]=prime[j]-a[i][j];
    }
    for(int j=0;j<3;j++)
      for(int i=0;i<prime[j];i++)
        f[i][j]=calc(i,j);
    bool flag;
    for(int i=1;i<=m;i++)
    {
        bool flag=true;
        for(int j=0;j<3;j++)
         if(f[i%prime[j]][j])
         {
            flag=false;break;
         }
        if(flag)cnt[++cnt[0]]=i;
    }
    printf("%d\n",cnt[0]);
    for(int i=1;i<=cnt[0];i++)
     printf("%d\n",cnt[i]);
    return 0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值