2016.6.8测试

1. ly的农场
【题目描述】
在农夫ly的农场里,有好多好多的奶牛,但是由于ly喂养得太好了,奶牛们越来越懒了,导致ly不得不采取些措施:要求它们每天早上晨跑,从A农场跑到B农场。从A农场到B农场中有n–2个路口,分别标上号,A农场为1号,B农场为n号,路口分别为2..n–1号,从A农场到B农场有很多条路径可以到达,而ly发现有的路口是必须经过的,即每条路径都经过的路口,ly要把它们记录下来,这样ly就可以先到那个路口,观察奶牛们有没有偷懒,而你的任务就是找出所有必经路口。
【输入文件】
第一行两个数n,m。
接下来m行,每行两个数u和v,表示路口u和v之间有路径直达。
输入数据保证必经路口一定存在,并且每个路口都和A,B农场直接或间接连通。
【输出文件】
第一行一个数m,表示必经路口数目。
接下来m行,按从小到大的顺序依次输出每个必经路口的编号。(不包括起点,终点)

【样例输入】
6 6
1 2
2 4
2 3
3 5
4 5
5 6
【样例输出】
2
2
5
【数据范围】
对于30%的数据,n ≤ 100,m ≤ 1000。
对于100%的数据,n ≤ 2000,m ≤ 8000。

正解:暴力。。。

解题报告:

  考场上面打的是tarjan,实际上举得出反例。其实直接暴力枚举就可以了,每次遍历全图,看不经过某点是否可以到达终点。

 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #include <stack>
14 #ifdef WIN32   
15 #define OT "%I64d"
16 #else
17 #define OT "%lld"
18 #endif
19 using namespace std;
20 typedef long long LL;
21 const int MAXN = 2011;
22 const int MAXM = 16011;
23 int n,m,ecnt,now;
24 int first[MAXN],next[MAXM],to[MAXM];
25 bool vis[MAXN];
26 bool ok;
27 int dui[MAXN],cnt;
28 
29 inline int getint()
30 {
31     int w=0,q=0;
32     char c=getchar();
33     while((c<'0' || c>'9') && c!='-') c=getchar();
34     if (c=='-')  q=1, c=getchar();
35     while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
36     return q ? -w : w;
37 }
38 
39 inline void link(int x,int y){
40     next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; 
41     next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x;
42 }
43 
44 inline void dfs(int x){
45     if(x==n) { ok=true; return ;}
46     vis[x]=1;
47     for(int i=first[x];i;i=next[i]){
48     int v=to[i];
49     if(!vis[v] && v!=now) dfs(v);
50     if(ok) return ;
51     }
52 }
53 
54 inline void solve(){
55     n=getint(); m=getint();
56     int x,y;
57     for(int i=1;i<=m;i++) {
58     x=getint(); y=getint();
59     link(x,y);
60     }
61 
62     for(int i=2;i<n;i++) {
63     now=i; ok=false;
64     memset(vis,0,sizeof(vis));
65     dfs(1);
66     if(!ok) dui[++cnt]=i;
67     }
68 
69     printf("%d
",cnt);
70     for(int i=1;i<=cnt;i++) {
71     printf("%d
",dui[i]);
72     }
73 }
74 
75 int main()
76 {
77     solve();
78     return 0;
79 }

2.xqz的难题
【题目描述】
xqz同学最近迷上了位运算,因为他天才般的头脑,题目都过于简单了。不过他今天ms状态不怎么好,被下面这道题打击到了,于是去寻找正在堕落的ld。题目如下:
给定一个数列,设计一个算法支持以下操作:
1. 插入一个数到数列的最后。
2. 在数列中找到一个值为k的数,将它从数列中删去。(数据保证数列中存在值为k的数,若有多个K值,任意删除1外)
3. 求值在L到R间的所有数依次进行xor的值。如果只有一个数满足条件,输出此数。
如果没有数满足,输出0。
(扫盲:xor在电脑的计算器里有,例如:7 xor 6 xor 3 = 2)
数列初始时为空。
【输入文件】
第一行,一个数m,表示操作的个数。
接下来有m行,对于每一行,首先一个数q:
若q=1,则后面一个数k(k ≤106),表示将k插入到数列的最后。
若q=2,则后面一个数k,表示将一个值为k的数删去。
若q=3,则后面两个数L和R,表示输出值在L到R间的所有数依次进行xor的值。

【输出文件】
对于每一个q=3的操作输出答案,每行一个数。
【样例输入】
5
1 5
1 6
3 1 10
2 5
3 1 8
【样例输出】
3
6
【数据范围】
对于30%的数据,m ≤ 2000。
对于100%的数据,m ≤ 100000,答案 ≤ 2^31 - 1。

正解:树状数组

解题报告:

  考场上又智障了。我的做法是先离线再离散化,然后树状数组,然而写萎了。实际上直接树状数组不用任何优化就可以了,毕竟只有10的6次方。。。

  异或有很多神奇的性质,这道题就体现了这一点。

  代码又短又快。

 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #ifdef WIN32   
14 #define OT "%I64d"
15 #else
16 #define OT "%lld"
17 #endif
18 using namespace std;
19 typedef long long LL;
20 const int MAXM = 1000011;
21 int a[MAXM];
22 int n=1000000,m;
23 
24 inline int getint()
25 {
26        int w=0,q=0;
27        char c=getchar();
28        while((c<'0' || c>'9') && c!='-') c=getchar();
29        if (c=='-')  q=1, c=getchar();
30        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
31        return q ? -w : w;
32 }
33 
34 inline void update(int x){
35     int val=x;
36     while(x<=n) {
37     a[x]^=val;
38     x+=( x&(-x) );
39     }
40 }
41 
42 inline int query(int x){
43     int total=0;
44     while(x>0) {
45     total^=a[x];
46     x-=( x&(-x) );
47     }
48     return total;
49 }
50 
51 inline void solve(){
52     m=getint();
53     int x,y; 
54     for(int i=1;i<=m;i++) {
55     int ljh=getint();
56     if(ljh==3) {
57         x=getint();y=getint();
58         printf("%d
",query(y)^query(x-1));
59     }
60     else{
61         x=getint();
62         update(x);
63     }
64     }
65 }
66 
67 int main()
68 {
69   solve();
70   return 0;
71 }

3.ld的棋盘
【题目描述】
(紧接上一题)“题目beng不难类!”xqz找到了ld,结果遭到了强烈的鄙视…怎么办类?xqz灵光一闪,拿出新买的一个“#”形棋盘,上面有24个格子(如下图)。这些格子上面
有1,2,3三种数字,且每种数字有8格。一开始,这些格子上的数字是随机分布的。ld的任务是移动这些格子使得中间8个格子的数字相同。有8种移动方式,分别标记为A到H,可以理解为拉动4条链,如图的变换为“AC”。问至少需要多少次拉动,才能从初始状态到达目标状态?(保证数据有解)ld顿时木了,于是求助作为OI高手的你。

(图略)

【输入文件】
有多组数据。每组数据包含一行,24个数字,表示从上到下从左到右表示棋盘上的数字。以0结束数据。(友情提示:请注意空间)
【输出文件】

每组数据一行,输出最少移动次数。
【样例输入】
1 1 1 1 3 2 3 2 3 1 3 2 2 3 1 2 2 2 3 1 2 1 3 3
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3
0
【样例输出】
2
4
【数据范围】
对于30%的数据,最大步数 ≤ 7,数据组数 ≤ 10。
对于60%的数据,最大步数 ≤ 12,数据组数 ≤ 20。
对于100%的数据,最大步数 ≤ 12,数据组数 ≤ 30。

正解:搜索

解题报告:

  北大信息学夏令营一试第一题,才从北京回来,今天考试又考到了这道题。。。

  只不过这道题稍稍弱化了一点。

  就直接搜索,迭代加深搜索,确定搜索次数上界,进行搜索。

  首先看一下中间的八个格子变成哪个数,1或者2或者3,3次枚举(剪枝:选择需要移动次数最少的)。

  确定完变成谁之后就枚举几种移动方式(字母),往下dfs。

  这样的话还是会TLE一个点,我们考虑避免一种情况,上一层往上移动,这一层又往下移动,这显然是没必要的,剪掉,就可以AC了。

  这题的翻版是POJ2286。

  1 //It is made by jump~
  2 #include <iostream>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <algorithm>
  8 #include <ctime>
  9 #include <vector>
 10 #include <queue>
 11 #include <map>
 12 #include <set>
 13 #ifdef WIN32   
 14 #define OT "%I64d"
 15 #else
 16 #define OT "%lld"
 17 #endif
 18 using namespace std;
 19 typedef long long LL;
 20 const int MAXC = 1011;
 21 int daan;
 22 /*
 23        0     1
 24        2     3
 25 4  5   6     7  8  9 10
 26       11    12
 27 13 14 15 16 17 18 19
 28       20    21
 29       22    23  */
 30 int mp[12][12]={{0,2,6,11,15,20,22}/*A*/,{1,3,8,12,17,21,23}/*B*/,{10,9,8,7,6,5,4}/*C*/,{19,18,17,16,15,14,13}/*D*/};
 31 int fan[12] = {5,4,7,6,1,0,3,2};
 32 int zhong[12] = {6,7,8,11,12,15,16,17};//中心的编号
 33 int a[45];
 34 
 35 inline int getint()
 36 {
 37     int w=0,q=0;
 38     char c=getchar();
 39     while((c<'0' || c>'9') && c!='-') c=getchar();
 40     if (c=='-')  q=1, c=getchar();
 41     while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
 42     return q ? -w : w;
 43 }
 44 
 45 inline bool already() {
 46     for(int i=0;i<=7;i++) if (a[zhong[i]]!=a[zhong[0]]) return false;
 47     return true;
 48 }
 49 
 50 inline int coun(int check) {
 51     int jishu=0;
 52     for(int i=0;i<8;i++)  if(a[zhong[i]]!=check) jishu++;
 53     return jishu;
 54 }
 55 
 56 inline int gu() {
 57     int ljh=coun(1);
 58     for(int i=2;i<=3;i++) //分别放1、2、3
 59     ljh=min(coun(i),ljh);
 60     return ljh;
 61 }
 62 
 63 inline void move(int x) {//往指定方向拉动一格
 64     int cun=a[mp[x][0]];
 65     for(int i=0;i<6;i++) a[mp[x][i]]=a[mp[x][i+1]];
 66     a[mp[x][6]]=cun;
 67 }
 68 
 69 inline bool dfs(int d,int maxd,int last) {
 70     if(already()) return true;
 71 
 72     if(d+gu()>maxd) return false;//超过上界
 73 
 74     for(int i=0;i<8;i++) {
 75     if(last==fan[i]) continue;
 76     move(i);
 77     if(dfs(d+1,maxd,i)) return true;
 78     move(fan[i]);//还原
 79     }
 80 
 81     return false;
 82 }
 83 
 84 inline void init(){
 85     fan[10]=-1;
 86     for(int i=4;i<=7;i++) 
 87     for(int j=0;j<=6;j++) 
 88         mp[i][j]=mp[fan[i]][6-j];
 89 }
 90 
 91 inline void solve(){
 92     init();
 93     int xx;
 94     while(scanf("%d",&xx)!=EOF && xx) {
 95     a[0]=xx; for(int i=1;i<=23;i++) scanf("%d",&a[i]);
 96     if(already())  printf("0
");       
 97         else {
 98         daan=1;
 99         for(;;daan++)
100         if(dfs(0,daan,10))  break;
101     }
102     printf("%d
",daan);
103     }
104 }
105 
106 int main()
107 {
108     solve();
109     return 0;
110 }

  

4.jx的游戏
【题目描述】
jx和ld一样,都在堕落……他现在正沉迷于一个国产数字游戏中。这个游戏看似简单,jx在研究了许多天看了许多次Game over的画面后却发觉,原来在简单的规则下想要赢得这个游戏并不那么容易。不过他发现了这个问题的简化版,即给定一个数列,找出1个连续数列使其和最大。但其本身的问题却很难解决:给定一个数列,找出3个无交集的连续数列使其和最大。显然,你的任务是解决这个原问题,好胜的jx很希望你能帮他解决这个问题赢得这个Game。
【输入文件】
第一行一个数n,表示数列长度。
接下来有n行,每行一个数,第i行为第i个数。
【输出文件】
仅有一个数,表示最大和。
【样例输入】
10
-1
2
3
-4
0
1
-6
-1
1
-2

【样例输出】
7
【数据范围】
数列是非空数列且长度大于等于3
对于30%的数据,n ≤ 200。
对于60%的数据,n ≤ 2000。
对于100%的数据,n ≤ 1000000,答案 ≤ 2^31 - 1。

正解:DP

解题报告:

  考场上没什么时间做这道题了。一眼秒题:DP。

  短时间内没有设计出状态。考完之后听llg的“满口鬼话”,听懂了这道题的状态。

  f[i][j][0、1]表示处理到第i个数,前i-1个数可以分成j块(j<=3),第i个数选或者不选的最大值   

  丧病出题人卡空间,滚动一下数组就可以了。

  转移还是很好想到的,O(1)转移,轻松AC。

 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #ifdef WIN32   
14 #define OT "%I64d"
15 #else
16 #define OT "%lld"
17 #endif
18 using namespace std;
19 typedef long long LL;
20 const int MAXN = 1000011;
21 int n,ans;
22 int f[2][4][2];
23 
24 inline int getint()
25 {
26        int w=0,q=0;
27        char c=getchar();
28        while((c<'0' || c>'9') && c!='-') c=getchar();
29        if (c=='-')  q=1, c=getchar();
30        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
31        return q ? -w : w;
32 }
33 
34 int main()
35 {
36   n=getint();
37 
38   int jilu=0;
39   for(int i=1;i<=n;i++) {
40       jilu=jilu^1;
41       int x=getint();
42       f[jilu][1][0]=max(f[!jilu][1][0],f[!jilu][1][1]);
43       f[jilu][1][1]=x+max(0,f[!jilu][1][1]);
44 
45       if(i>=2) {
46       f[jilu][2][0]=max(f[!jilu][2][0],f[!jilu][2][1]);
47       f[jilu][2][1]=max(f[!jilu][2][1],max(f[!jilu][1][1],f[!jilu][1][0]))+x;
48       }
49 
50       if(i>=3) {
51       f[jilu][3][0]=max(f[!jilu][3][0],f[!jilu][3][1]);
52       f[jilu][3][1]=max(f[!jilu][3][1],max(f[!jilu][2][1],f[!jilu][2][0]))+x;
53       }
54 
55       ans=max(f[jilu][3][0],f[jilu][3][1]);
56   }
57 
58   printf("%d",ans);
59   return 0;
60 }
原文地址:https://www.cnblogs.com/ljh2000-jump/p/5570195.html