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\n",cnt);
70 for(int i=1;i<=cnt;i++) {
71 printf("%d\n",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\n",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\n");
97 else {
98 daan=1;
99 for(;;daan++)
100 if(dfs(0,daan,10)) break;
101 }
102 printf("%d\n",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