是惹某人没想到的偷懒的开学第一周(习题+感悟)

(一)洛谷

A - P1605 迷宫

题目描述

    给定一个N*M方格的迷宫,迷宫里有T处障碍,障碍处不可通过。给定起点坐标和终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案。在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。

Input

第一行N、M和T,N为行,M为列,T为障碍总数。第二行起点坐标SX,SY,终点坐标FX,FY。接下来T行,每行为障碍点的坐标。

Output

给定起点坐标和终点坐标,问每个方格最多经过1次,从起点坐标到终点坐标的方案总数。

Sample Input

2 2 1
1 1 2 2
1 2

Sample Output

1

说明/提示

【数据规模】

1≤N,M≤5

理解

虽然只是个普通的dfs。。我wa了三次,然后血与泪的教训是我没有把起点标记为1(已走过)
然后一直40分!!!忍不住看了题解...啊大佬们说40分就是起点没标记的结果!!!我恨

AC代码

#include <bits/stdc++.h>
using namespace std;
int a[6][6];
int cnt;
int sx,sy,fx,fy;
int n,m,t;
int dir[4][2]={
	{0,1},
	{0,-1},
	{1,0},
	{-1,0},
};
void dfs(int x,int y){
	if(x == fx && y == fy){
		cnt++;
		return;
	}
	for(int i = 0;i < 4;i++){
		x += dir[i][0];
		y += dir[i][1];
		if(a[x][y] == 0 && x >= 1 && x <= n && y >= 1 && y <= m){
			a[x][y] = 1;
			dfs(x,y);
			a[x][y] = 0;
		}
		x -= dir[i][0];
		y -= dir[i][1];	
	}
	return;
}

int main(){
	cin >> n >> m >> t;
	cin >> sx >> sy >> fx >> fy;
	memset(a,0,sizeof(a));
	a[sx][sy] = 1;
	while(t--){
		int c,d;
		cin >> c >> d;
		a[c][d] = 1;
	}
	cnt = 0;
//	for(int i = 1;i <= n;i++){
//		for(int j = 1;j <= m;j++){
//			printf("%d ",a[i][j]);
//		}
//		printf("\n");
//	}
	dfs(sx,sy);
	cout << cnt << endl;
	return 0;
}

B - P1141 01迷宫

题目描述

    有一个仅由数字00与11组成的n \times nn×n格迷宫。若你位于一格0上,那么你可以移动到相邻44格中的某一格11上,同样若你位于一格1上,那么你可以移动到相邻44格中的某一格00上。
你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。

Input

    第11行为两个正整数n,mn,m。
    下面nn行,每行nn个字符,字符只可能是00或者11,字符之间没有空格。
     接下来mm行,每行22个用空格分隔的正整数i,ji,j,对应了迷宫中第ii行第jj列的一个格子,询问从这一格开始能移动到多少格。 然后T行,每行为一个数N(1<=N<=1000000)表示长方形的大小。

Output

    m行,对于每个询问输出相应答案。

Sample Input

2 2
01
10
1 1
2 2

Sample Output

4
4

说明/提示

所有格子互相可达。
对于20%20%的数据,n≤10n≤10;
对于40%40%的数据,n≤50n≤50;
对于50%50%的数据,m≤5m≤5;
对于60%60%的数据,n≤100,m≤100n≤100,m≤100;
对于100%100%的数据,n≤1000,m≤100000n≤1000,m≤100000。

理解

这一题我起先细节错误没有加=然后我就wa了,当然wa中还坚定地带着三个tle
然后我康了好久的代码,改完后其他的样例都A了,顽强的三个tle依旧在,果然是查询次数太多了不能一次次查询么
然后就默默改了QAQ

AC代码

#include<bits/stdc++.h>
using namespace std;
int mp[1005][1005]; //保存地图 
int v[1005][1005],a[1000005]; 
struct node{
	int x,y;
}zb[1000005];
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0},};
int main(){
	int n,m,cnt;
	cin >> n >> m;
	char c;
	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= n;j++){
			cin >> c;
			if(c == '1') mp[i][j] = 1;
			else mp[i][j] = 0;
		}
	}
	int d = 0,f,r;
	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= n;j++){
			if(v[i][j] == 0){
				d++;
				f = 1;
				r = 1;
				zb[f].x = i;
				zb[f].y = j;
				v[i][j] = d;
				cnt = 1;
				while(f <= r){
					for(int k = 0;k < 4;k++){
						int x1 = zb[f].x + dir[k][0];
						int y1 = zb[f].y + dir[k][1];
						if(v[x1][y1]== 0 && x1 >= 1 && y1 >= 1 && x1 <= n && y1 <= n
						&& (( mp[x1][y1] == 1 && mp[zb[f].x][zb[f].y] == 0) ||
						(mp[x1][y1] == 0 && mp[zb[f].x][zb[f].y] == 1)) ){
							r++;
							cnt++;
							v[x1][y1] = d;
							zb[r].x = x1;
							zb[r].y = y1;
						}
					}
					f++;
				}
				a[d] = cnt;
			}
		}
	}
	int sx,sy;
	for(int i = 1;i <= m;i++){
		cin >> sx >> sy;
		cout << a[v[sx][sy]] << endl;
	}
	return 0;
}

C - P1019 单词接龙

题目描述

    单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beastbeast和astonishastonish,如果接成一条龙则变为beastonishbeastonish,另外相邻的两部分不能存在包含关系,例如atat 和 atideatide 间不能相连。

Input

    输入的第一行为一个单独的整数n (n≤20)表示单词数,以下n 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.

Output

    只需输出以此字母开头的最长的“龙”的长度

Sample Input

5
at
touch
cheat
choose
tact
a

Sample Output

23

说明/提示

样例(连成的“龙”为atoucheatactactouchoose)
NOIp2000提高组第三题

理解

本来写的时候用了挺蠢的方法、、、然后连样例都不对
后来大佬点拨我说可以用数组存两个字符串的重叠部分的长度

AC代码

#include<bits/stdc++.h>
using namespace std;
string s[30];
int cd[30][30]; //计算i和j重叠部分的长度 
int v[30];
int len = 0;
int ans = -1;
int n;
int func(int x,int y){
	bool f = true;
	int idx = 0;
	for(int k = s[x].size()-1;k >= 0;k--){
		for(int l = k;l < s[x].size();l++){
			if(s[x][l] != s[y][idx++]){
				f = false;
				break;
			}
		}
		if(f){
			return s[x].size()-k;
		}
		idx = 0;
		f = true;
	}
	return 0;
}
void dfs(int t){
	bool flag = false;
	for(int j = 1;j <= n;j++){
		if(v[j] >= 2) continue; //使用超过两次
		if(cd[t][j] == 0) continue; //不重叠
		//两者包含 
		if(cd[t][j] == s[t].size() || cd[t][j] ==s[j].size()) continue;
		len += s[j].size() - cd[t][j];
		v[j]++;
		flag = true;
		dfs(j);
		len -= s[j].size() - cd[t][j];
		v[j]--;
	}
	if(!flag){
		ans = max(ans,len);
	}
	return;
}
int main(){
	cin >> n;
	for(int i = 1;i <= n;i++){
		cin >> s[i];
	}
	char c; cin >> c;
	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= n;j++){
			//计算最小重叠部分 
			cd[i][j] = func(i,j); 
		}
	}
	for(int i = 1;i <= n;i++){
		if(s[i][0] == c){
			v[i]++;
			len = s[i].size();
			dfs(i);
			v[i] = 0;
		}
	}
	cout << ans << endl;
	return 0;
} 

D - icpc上海网络赛 Light bulbs

题目描述

    There are NN light bulbs indexed from 0 to N−1. Initially, all of them are off.
    A FLIP operation switches the state of a contiguous subset of bulbs. FLIP(L, R) means to flip all bulbs xx such that L≤x≤R. So for example,FLIP(3,5)FLIP(3,5) means to flip bulbs 33 , 44 and 55, and FLIP(5, 5)FLIP(5,5) means to flip bulb 55.
    Given the value of NN and a sequence of M flips, count the number of light bulbs that will be on at the end state.

Input

The first line of the input gives the number of test cases, T. T test cases follow. Each test case starts with a line containing two integers N and M, the number of light bulbs and the number of operations, respectively. Then, there are M more lines, the i-th of which contains the two integers Li and Ri,indicating that the i-th operation would like to flip all the bulbs from Li to Ri, inclusive.
1≤T≤1000
1≤N≤1e6
1≤M≤1000
0 ≤ Li​ ≤ Ri ≤ N−1

Output

For each test case, output one line containing Case #x: y, where xx is the test case number (starting from 11) and yy is the number of light bulbs that will be on at the end state, as described above.

Sample Input

2
10 2
2 6
4 8
6 3
1 1
2 3
3 4

Sample Output

Case #1: 4
Case #2: 3

理解

这道题卡死了一片人。。暴力法存普通数组tle了6ms,然后改了map结果超了内存。。。然后开始头铁
不停地莽交,甚至他们还妄图用玄学做法A这道题!!!然鹅并没有用,果然这道题就是为了卡我们这些暴力循环的小胖友的
最后其他的题目看了看都打算放弃惹。。然后不死心的map改hashmap再试一次继续t,然后改了快读变成了wa、、惊奇操作
最后!!!感恩吴某人过来和我讲了他的未尝试的思路!!!如此的清奇!!!本来只是trytry,结果就A了!我的天!

AC代码

#include <bits/stdc++.h>
using namespace std;
int mp[2005];
int main(){
	int T;
	scanf("%d",&T);
	for(int i=1;i<=T;i++){
		int n,m;
		scanf("%d%d",&n,&m);
		int wz = 0;
		for(int j=0;j<m;j++){
			int l,r;
			scanf("%d%d",&l,&r);
			mp[wz++] = l;
			mp[wz++] = r+1;
		}
		sort(mp,mp+wz);
		int sum = 0;
		for(int j = 1;j < wz;j += 2){
			sum += mp[j]-mp[j-1];
		}
		printf("Case #%d: %d\n",i,sum);
	}
	return 0;
}

(三)我的感想(die)

关于这周的日常练习

开学一周, 似乎轻松了一些(并不),划划水的日子里。。也不知道自己在瞎忙些什么。。下周不可以这样了哦!!!

关于icpc的网络赛

啊没有大佬带队的时候,就慌得一批,还好唐龙能C我,沈阳赛我们就写了一个水题,然后尝试写过的题都是别人通过率贼低,果然是选错题目了,我还以为都是签到题(明明是自己想的太过简单了)然后上海赛卡死B,也就是上面解析的那题。。。嘤嘤嘤,然后看别人签到了L,就去签了L,在放弃的边缘,终于A了。。。而且还是听了大佬的新思路,收回上周的话,暴力法未必天下第一…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值