NOIP 2014 题解

好吧,15年写14年题解,的确够晚的(P.S. 是因为我到现在才搞懂这些题)

正文之前,先膜拜膜拜一位大爷 %%% _debug

多膜拜膜拜 _debug 大爷,打程序时bug会减少哦

传送门:

生活大爆炸版石头剪刀布:  http://codevs.cn/problem/3716/

联合权值:         http://codevs.cn/problem/3728/

飞扬的小鸟:        http://codevs.cn/problem/3729/

无线网络发射器选址:    http://codevs.cn/problem/3578/

寻找道路:         http://codevs.cn/problem/3731/

解方程:          http://codevs.cn/problem/3732/

这里讲题的顺序:由易到难

Day1 T1 与 Day2 T1

这两题若是不会做,建议你先搜搜A+B problem的题解

直接上代码了

P.S. 代码是pascal的 这是我14年考试时的代码 14年我不会用C (QAQ)

Day1 T1

 1 var
 2  n,na,nb,i,j,win1,win2,ls1,ls2:longint;
 3  a,b:array[0..200]of longint;
 4  p:array[0..4,0..4]of 0..2;
 5 begin
 6  readln(n,na,nb);
 7  for i:=1 to na do read(a[i]);
 8  for i:=1 to nb do read(b[i]);
 9  p[0,0]:=0; p[0,1]:=2; p[0,2]:=1; p[0,3]:=1; p[0,4]:=2;
10  p[1,0]:=1; p[1,1]:=0; p[1,2]:=2; p[1,3]:=1; p[1,4]:=2;
11  p[2,0]:=2; p[2,1]:=1; p[2,2]:=0; p[2,3]:=2; p[2,4]:=1;
12  p[3,0]:=2; p[3,1]:=2; p[3,2]:=1; p[3,3]:=0; p[3,4]:=1;
13  p[4,0]:=1; p[4,1]:=1; p[4,2]:=2; p[4,3]:=2; p[4,4]:=0;
14  win1:=0; win2:=0;
15  for i:=1 to n do
16  begin
17   ls1:=a[(i-1) mod na+1];
18   ls2:=b[(i-1) mod nb+1];
19   if p[ls1,ls2]=1 then inc(win1);
20   if p[ls1,ls2]=2 then inc(win2);
21  end;
22  writeln(win1,‘ ‘,win2);
23 end.

Day2 T1

 1 var
 2  i,j,l,n,d,ans,x,y,k,ans1,ans2,max1,max2,left,right,up,down:longint;
 3  sum:array[-1..128,-1..128]of longint;
 4 function min(a,b:longint):longint;
 5 begin
 6  if a<b then exit(a) else exit(b);
 7 end;
 8 function max(a,b:longint):longint;
 9 begin
10  if a>b then exit(a) else exit(b);
11 end;
12 begin
13  readln(d); readln(n); max1:=0; max2:=0;
14  for i:=1 to n do
15  begin
16   readln(x,y,k);
17   max1:=max(x,max1);
18   max2:=max(y,max2);
19   for j:=x to 128 do
20   for l:=y to 128 do
21   inc(sum[j,l],k);
22  end;
23  for i:=0 to min(128,max1+2*d) do
24  for j:=0 to min(128,max2+2*d) do
25  begin
26   up:=max(0,i-d);
27   down:=min(128,i+d);
28   left:=max(0,j-d);
29   right:=min(128,j+d);
30   l:=sum[down,right]-sum[down,left-1]-sum[up-1,right]+sum[up-1,left-1];
31   if l>ans2 then begin ans1:=1; ans2:=l; end
32   else if l=ans2 then inc(ans1);
33  end;
34  writeln(ans1,‘ ‘,ans2);
35 end.

Day1 T2 联合权值

记录每个点的儿子节点权值的 和(sum[])、最大值(max1[])、次大值(max2[])

令数组w[]记录每个点的权值

令ans1记录联合权值最大值,ans2记录联合权值和

以1为树的根,全部BFS一遍,在BFS中

对于每一次搜到的点 u

ans1=max(ans1,max1[u]*max2[u])

对于每一次搜到的边 u--->v

ans1=max(ans1,w[u]*max1[v])
ans2+=w[v]*(sum[u]-w[v])
ans2+=w[u]*sum[v]*2

大概就是这样了

代码如下

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 #define LL long long
 7 const int maxn=200000+10;
 8 int n,m,i,j,w[maxn],sum[maxn],max1[maxn],max2[maxn];
 9 int aa[maxn],bb[maxn],ans1,ans2;
10 struct node{
11        int v;
12        node *next;
13 };
14 node *g[maxn],*p;
15 void add(int u,int v)
16 {
17      p=new(node);
18      p->v=v;
19      p->next=g[u];
20      g[u]=p;
21 }
22 int dui[maxn],h,t;
23 int max(int a,int b) {return a>b?a:b;}
24 int min(int a,int b) {return a<b?a:b;}
25 int main()
26 {
27     scanf("%d",&n);
28     for (i=1;i<n;i++)
29     {
30         int a,b;
31         scanf("%d%d",&a,&b);
32         if (a>b) {int t=a;a=b;b=t;}
33         add(a,b);
34         aa[i]=a; bb[i]=b;
35     }
36     for (i=1;i<=n;i++) scanf("%d",&w[i]);
37     for (i=1;i<n;i++)
38     {
39         int a=aa[i],b=bb[i];
40         sum[a]+=w[b];
41         sum[a]%=10007;
42         if (w[b]>=max1[a]) max2[a]=max1[a],max1[a]=w[b];
43         else max2[a]=max(max2[a],w[b]);
44     }
45     h=0; t=1; dui[1]=1;
46     while (h!=t)
47     {
48           h++;
49           int u=dui[h];
50           ans1=max(ans1,max2[u]*max1[u]);
51           p=g[u];
52           while (p!=NULL)
53           {
54                 dui[++t]=p->v;
55                 int v=p->v;
56                 ans1=max(ans1,w[u]*max1[v]);
57                 ans2+=w[v]*(sum[u]-w[v]);
58                 ans2+=w[u]*sum[v]*2;
59                 ans2%=10007;
60                 p=p->next;
61           }
62     }
63     ans2%=10007;
64     printf("%d %d\n",ans1,ans2);
65 }

记得ans2要对10007取模

Day2 T2寻找道路

傻B题

思路大概是,先把所有边反向,从终点来一次DFS/BFS,标记所有经过了的点

然后会有一些没标记的点,这些就是走不到终点的

在原图上,把指向走不到终点的点的点删掉(这句话有点绕,多绕绕就会绕了)

再从起点来一遍SPFA

好吧,就这么简单

P.S. 去年在考场上时是想到了这个方法的,可惜邻接表不会打,打了个邻接矩阵,70分 (QAQ)

废话不多说,代码如下

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 #define LL long long
 7 const int maxn=10000+10;
 8 const int INF=10000000;
 9 int n,m,i,j,a[maxn],S,T,dis[maxn];
10 int Q[maxn],h,t;
11 int max(int a,int b) {return a>b?a:b;}
12 int min(int a,int b) {return a<b?a:b;}
13 struct node{
14        int v;
15        node *next;
16 };
17 node *g[maxn],*g2[maxn],*p;
18 bool in[maxn];
19 node *add(int u,int v,node *nd)
20 {
21      node *p;
22      p=new(node);
23      p->v=v;
24      p->next=nd;
25      return p;
26 }
27 void spfa()
28 {
29      int i,j;
30      node *p;
31      for (i=0;i<=n;i++) dis[i]=INF,in[i]=0;
32      h=0; t=1; dis[S]=0; in[S]=0; Q[1]=S;
33      while (h!=t)
34      {
35            h++;
36            int u=Q[h];
37            p=g[u];
38            while (p!=NULL)
39            {
40                  int v=p->v;
41                  if (dis[u]+1<dis[v])
42                  {
43                      dis[v]=dis[u]+1;
44                      if (!in[v]) Q[++t]=v,in[v]=1;
45                  }
46                  p=p->next;
47            }
48            in[u]=0;
49      }
50 }
51 int main()
52 {
53     scanf("%d%d",&n,&m);
54     for (i=1;i<=m;i++)
55     {
56         int a,b;
57         scanf("%d%d",&a,&b);
58         g[a]=add(a,b,g[a]);
59         g2[b]=add(b,a,g2[b]);
60     }
61     scanf("%d%d",&S,&T);
62     h=0; t=1; Q[1]=T; in[T]=1;
63     while (h!=t)
64     {
65           h++;
66           int u=Q[h];
67           p=g2[u];
68           while (p!=NULL)
69           {
70                 if (!in[p->v]) Q[++t]=p->v,in[p->v]=1;
71                 p=p->next;
72           }
73     }
74     if (!in[S]) {printf("-1\n"); return 0;}
75     for (i=1;i<=n;i++)
76     if (!in[i])
77     {
78         p=g2[i];
79         while (p!=NULL)
80         {
81               if (p->v==S) {printf("-1\n"); return 0;}
82               g[p->v]=NULL;
83               p=p->next;
84         }
85     }
86     spfa();
87     if (dis[T]==INF) {printf("-1\n"); return 0;}
88     printf("%d\n",dis[T]);
89 }

Day1 T3 飞扬的小鸟

P.S. 每次看到“飞扬的小鸟”我就觉得我是手残

大爷一眼就能看出要用DP做,唯我第一想法是暴搜

dp[i][j]——小鸟飞到 第i列 高度为j的地方时,最少点击次数

令数组U[i]记录在第i-1列点击一次上升的高度

数组D[i]记录在第i-1列不点击下降的高度

边界条件:dp[0][0]=INF ; dp[0][j]=0 (j=1...m)

转移方程:

1)上升  dp[i][j]=min(dp[i][j],dp[i][j-U[i]]+1,dp[i-1][j-U[i]]+1);

2)下降  dp[i][j]=min(dp[i][j],dp[i-1][j+D[i]]);

3)j=m要特判

这一题更加详细的题解我会在以后写出

请关注我的博客http://www.cnblogs.com/Donnie-Darko/

(P.S. 其实现在我的博客里也没什么东西,上面那句话本身想删了的,可是再想一想又觉得,脸皮还是厚点好)

代码如下

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 #define LL long long
 7 const int maxn=10000+10;
 8 const int maxm=1000+10;
 9 const int INF=100000;
10 int n,m,i,j,k,dp[maxn][maxm],U[maxn],D[maxn],ans=0;
11 bool pass[maxn][maxm],conduit[maxn];
12 int max(int a,int b) {return a>b?a:b;}
13 int min(int a,int b) {return a<b?a:b;}
14 int main()
15 {
16     scanf("%d%d%d",&n,&m,&k);
17     for (i=0;i<=n;i++) pass[i][0]=1;
18     for (i=1;i<=n;i++)
19     scanf("%d%d",&U[i],&D[i]);
20     for (i=1;i<=k;i++)
21     {
22         int a,b,c;
23         scanf("%d%d%d",&a,&b,&c);
24         conduit[a]=1;
25         for (j=0;j<=b;j++) pass[a][j]=1;
26         for (j=c;j<=m;j++) pass[a][j]=1;
27     }
28     dp[0][0]=INF;
29     for (i=1;i<=n;i++)
30     {
31         for (j=0;j<=m;j++) dp[i][j]=INF;
32         for (j=U[i]+1;j<m;j++)
33         {
34             dp[i][j]=min(dp[i][j],dp[i][j-U[i]]+1);
35             dp[i][j]=min(dp[i][j],dp[i-1][j-U[i]]+1);
36         }
37         for (j=0;j<=m-D[i];j++)
38         dp[i][j]=min(dp[i][j],dp[i-1][j+D[i]]);
39         for (int o=1;o<=m;o++)
40         {
41             int p=(m-o)/U[i];
42             if ((m-o)%U[i]!=0||p==0) p++;
43             dp[i][m]=min(dp[i][m],dp[i-1][o]+p);
44         }
45         int minl=INF;
46         for (j=0;j<=m;j++) if (pass[i][j]) dp[i][j]=INF;
47         for (j=0;j<=m;j++) minl=min(minl,dp[i][j]);
48         if (minl==INF) break;
49         if (conduit[i]) ans++;
50     }
51     if (ans<k) printf("0\n%d\n",ans);
52     else
53     {
54         ans=INF;
55         for (i=1;i<=m;i++) ans=min(ans,dp[n][i]);
56         printf("1\n%d\n",ans);
57     }
58 }

Day2 T3 解方程

每次看到这种数学题就想弃疗

这题,要用模糊一点的方法做

也就是枚举x,算答案时不停对10007取模,若最后的答案是0,就当成正确答案了(连long long都不要用)

当然,天知道出数据的人会不会整个变态数据卡10007

所以我准备了5个模数{11261,19997,22877,21893,14843},只有答案全为0,才认为是正确答案

你来卡我啊,卡我啊,我看你怎么卡

于是这题就愉快的AC了

等等,细心的同学发现了,这样会超时,唉,上面那句话当我没说好了

大家可以发现,在模p意义下

如果x0不是答案

那么在模p意义下,x0+p不是答案,x0+2p也不是答案......

时间复杂度瞬间下降对不对

还是那句话,这一题更加详细的题解我会在以后写出

请关注我的博客http://www.cnblogs.com/Donnie-Darko/

(P.S. 记得电视上的广告脸皮厚到能连播三遍,我说两遍又有什么错)

代码如下

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 char s[10010];
 7 int n,m,i,j,a[5][1000010];
 8 bool ok[5][1000010];
 9 int mod[5]={11261,19997,22877,21893,14843};
10 bool pass(char c){return ((‘0‘<=c&&c<=‘9‘)||c==‘-‘);}
11 int ans[1000010];
12 int min(int a,int b) {return a<b?a:b;}
13 bool jud(int x)
14 {
15      for(int t=0;t<5;t++)
16      if(ok[t][x%mod[t]]!=0)return 0;
17      return 1;
18 }
19 void R(int p)
20 {
21      scanf("%s",s+1);
22      int len=strlen(s+1);
23      bool flag=0;
24      for (int t=0;t<5;t++)
25      if(s[1]!=‘-‘) a[t][i]=s[1]-‘0‘;
26      else a[t][i]=0,flag=1;
27      for (int t=0;t<5;t++)
28      {
29          for (int k=2;k<=len;k++)
30          a[t][i]=(a[t][i]*10+s[k]-‘0‘)%mod[t];
31          if (flag) a[t][i]=-a[t][i];
32      }
33 }
34 int main()
35 {
36     scanf("%d%d",&n,&m);
37     for (i=0;i<=n;i++) R(i);
38     int pre[5][110],res[5];
39     for (i=0;i<=4;i++) pre[i][0]=1;
40     for (int x=1;x<=min(m,22877-1);x++)
41     {
42         for (j=0;j<=4;j++)
43         for (i=1;i<=n;i++)
44         pre[j][i]=(pre[j][i-1]*x)%mod[j];
45         for (i=0;i<=4;i++) res[i]=0;
46         for (i=0;i<=n;i++)
47         for (j=0;j<=4;j++)
48         if (x<mod[j])
49         res[j]+=(pre[j][i]*a[j][i])%mod[j],res[j]%=mod[j];
50         for (i=0;i<=4;i++) if (res[i]&&x<mod[i]) ok[i][x]=1;
51     }
52     for (i=1;i<=m;i++) if (jud(i)) ans[++ans[0]]=i;
53     printf("%d\n",ans[0]);
54     for (i=1;i<=ans[0];i++) printf("%d\n",ans[i]);
55 }
时间: 2024-08-07 07:14:50

NOIP 2014 题解的相关文章

NOIP 2014 提高组 题解

NOIP 2014 提高组 题解 No 1. 生活大爆炸版石头剪刀布 http://www.luogu.org/problem/show?pid=1328 这是道大水题,我都在想怎么会有人错了,没算法,直接模拟,别读错题. 1 int wn[5][5]={{2,0,1,1,0}, 2 {1,2,0,1,0}, 3 {0,1,2,0,1}, 4 {0,0,1,2,1}, 5 {1,1,0,0,2}}; 6 7 int n,na,nb; 8 int a[222],b[222]; 9 int s1,s

NOIP 2012 题解

[D1T1vigenere密码] P1778vigenere密码 Accepted 标签:[显示标签] 描述 16世纪法国外交家Blaise de Vigenère设计了一种多表密码加密算法--Vigenère密码.Vigenère密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为南军所广泛使用. 在密码学中,我们称需要加密的信息为明文,用M表示:称加密后的信息为密文,用C表示:而密钥是一种参数,是将明文转换为密文或将密文转换为明文的算法中输入的数据,记为k. 在Vigenère

NOIP 2010 题解

[前言]最近这的很少弄OI了,虽说是暑假.趁要把NOIP2010~2013的题刷完,我做完一份便写一篇题解吧. [P1774机器翻译] P1774机器翻译 Accepted 标签:[显示标签] 描述 小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章. 这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换.对于每个英文单词,软件会先在内存中查找这个单词的中文含义,如果内存中有,软件就会用它进行翻译:如果内存中没有,软件就会在外存中的词典内查找,查出单

NOIP 2010题解

唔..NOIP2010比较简单,总体感觉不错. Problem 1: 机器翻译 水题,队列的简单应用. 读入时判断是否在内存中,可以用hash优化.如果不在内存中push进内存,放不下了pop header不用说了.上代码(未hash优化) //Bazinga! #include "cstdio" int sum,i,m,n; struct Q{ int len,head,tail,qub[1001],i; void push(int n){ qub[tail]=n; ++tail;

NOIP 2014民间题解

Day1 T1 这个题其实就是考你会不会编程. T2 题目有坑点,说n个点的无向图上有n-1条边,很明显这是棵树. 因为是树,所以我们没必要跑最短路,而且世界上还没这么快的最短路算法能A掉这个题. 下面是ydc的思路 考虑距离为2的点对,可以理解为枚举i,i能走到的点集两两之间距离为2 我们要做的是对于一个数组a1,a2,a3,-,am,要求aiaj,i≠j的Σ与max max是个很简单的事情,你只要求a数组的最大值与次大值即可 至于Σ,我们知道∑i=1n∑j=1naiaj=(∑i=1nai)2

[NOIP 2014普及T4] 子矩阵题解

洛谷P1328==codevs3716 生活大爆炸版石头剪刀布[NOIP 2014 day1 T1]

P1328 生活大爆炸版石头剪刀布 1.8K通过 2.6K提交 题目提供者2014白永忻 标签模拟NOIp提高组2014 难度普及- 提交该题 讨论 题解 记录 最新讨论 Who can help me(+﹏+)~ hehe 我去 数据错误 题目描述 石头剪刀布是常见的猜拳游戏:石头胜剪刀,剪刀胜布,布胜石头.如果两个人出拳一样,则不分胜负.在<生活大爆炸>第二季第8 集中出现了一种石头剪刀布的升级版游戏. 升级版游戏在传统的石头剪刀布游戏的基础上,增加了两个新手势: 斯波克:<星际迷航

NOIP 2014 解方程

今天重新做了一下NOIP原题,当时啥也不会,就直接输出0,搞了10分,今天看看撑死也就30,50了,用了网上的一种hash法勉强搞到70分,AC的还未看懂,下面给个标准的题解吧,争取早日理解. 30% : 穷举x,判断等式是否成立. 50% : 在30%的做法中加入高精度乘法,加法.不用高精减的原因是,只要把符号相同的项移到等式一边,最后再计算等式两边数值是否相等.同时记得要写秦九韶(霍纳法则)优化. 70% : 根据同余的性质,同余符号两边可以支持同加一个数,同乘一个数.那么可以对等式两边同时

noip 2014 总结

2014 年的noip 已经结束了,成绩从个人而言不是特别的理想,从今年题的逗的程度,本来是个xxx 就被玩脱了= = 当然现在后悔事没有用的了,不过第二天全屏技术的在最后一小时看到了两道题的错误,然后才把它们给ac了. 不得不说rp不错啊-不过就结果而言一等奖拿到了并且和前面的差距不大,也就没什么问题. 从具体考试情况分析,还是那句话只要吧该拿的分拿到了就没什么问题,比如今年妥妥的把前四道a了然后day1T3 75 day2T3 50 就是全省10以上了==所以我们得抱着一个爆0的心去考试才能