大一上第十四周学习笔记

这周就是刷cf和周末校赛,加油

 

12.14 周一

 

Codeforces Round #685 (Div. 2)

C. String Equality

这题一开始看到有交换的操作,联想到冒泡排序,就意识到其实是可以有任意的顺序的

所以题目给的字符串的顺序就不重要了,第二个操作相邻的问题也不用考虑的

但接下来怎么利用第二个操作就卡住了

有想到把每个字母统计出来,但觉得这个k非常非常的麻烦,只能连续k个才能变,不知道怎么处理这个k

然后就卡了一个小时没有什么思路,就看题解了

有思考但长时间没有什么思路就可以看题解,想不出没关系,积累经验,博客尤其好好总结没想出来的题目

 

题解有几个关键的点,也是之前一直卡住我的点

(1)如果目标字符串没有出现这个字符怎么整。我之前想的是那就不遍历了,这大大增加了思维难度,这弄得我都不知道该具体如何把

两个字符串的字符遍历一遍了。正确做法就是看作0个字符,和字符存在的1个字符,2个字符是等价了

这样就可以把字符不存在的情况归到一种通用的情况中。这和有些题把0看作跟节点的思想类似,把特殊情况归进来

(2)既然不存在看作0,那就可以每一个相同的字母比较了。这里关键的一点是,如果有多出来的字母而且是字母数是k的倍数,那就可以

加给下一个字母。下一个字母能用上就能用,不能用上还会给下下个字母。这就解决了我之前不知道怎么处理这个k的问题

可以从最开始的a开始想这个问题

(3)以后写完cf题后看题解的思路以及题解的代码。这个题解的代码就有我值得学习的地方。

比如变量的名称表示意义,判断的过程顺便处理

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)  
using namespace std;

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		int n, k;
		scanf("%d%d", &n, &k);
		
		int have[30] = {0}, need[30] = {0};
		getchar(); _for(i, 1, n) have[getchar() - 'a']++;
		getchar(); _for(i, 1, n) need[getchar() - 'a']++;
		
		int flag = 1;
		REP(i, 0, 26)
		{
			if(have[i] < need[i] || (have[i] -= need[i]) % k)
			{
				flag = 0;
				break;
			}
			have[i+1] += have[i];
		}
		
		if(flag) puts("Yes");
		else puts("No");
	}
	
	return 0;
}

 

Educational Codeforces Round 98 (Rated for Div. 2)

赛前第四套cf题

A. Robot Program

注意矩阵的坐标和坐标系的坐标的区别,我在这里弄混了

我还有个地方理解错了,row是对于矩阵而言,而在坐标系中就是同一个x或同一个y

因为这些卡了一下

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)  
using namespace std;

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		int x, y;
		scanf("%d%d", &x, &y);
		printf("%d\n", max(2 * x - 1, 2 * y - 1) + (x == y));
	}
	return 0;
}

C. Two Brackets

水题

本来想到用栈的,然后发现不需要

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)  
using namespace std;

const int MAXN = 2e5 + 10;
char s[MAXN];

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		scanf("%s", s);
		int ans = 0, sum1 = 0, sum2 = 0;
		REP(i, 0, strlen(s))
		{
			if(s[i] == '(') sum1++;
			if(s[i] == '[') sum2++;
			if(s[i] == ')' && sum1) sum1--, ans++;
			if(s[i] == ']' && sum2) sum2--, ans++;
		}
		printf("%d\n", ans);
	}
	return 0;
}

 

明天做BD题,加油

 

12.15 周二

 

B. Toy Blocks

这题想出了一半,后一半卡住了,卡了2个小时,最后就看题解了
我自己推出要满足必须符合两个条件
sum能被n-1整除,而且sum / (n - 1) >= ma
但我不知道该怎么算要加的木块数
实际上直接从最后摆完的状态去考虑会简单很多,上两个条件也很容易推出
我原来想的是几块几块加上去直到符合条件,结果很难想
实际上这个两个条件可以直接推出结果的状态
我原来一直在纠结过程,没有考虑最后的结果是怎么样的
可以推出最后的高度k就是max(sum / (n-1), ma),前式向上取整
然后就算出最后所有的块数减去一开始的块数就可以了
答案那个向上取整的写法要学习 

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)  
using namespace std;

typedef long long ll;
int ma, n;
ll sum;

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		scanf("%d", &n);
		ma = sum = 0;
		_for(i, 1, n)
		{
			int x; scanf("%d", &x);
			ma = max(ma, x);
			sum += x;
		}
		
		ll k = max((sum + n - 2) / (n - 1), (ll)ma);
		printf("%lld\n", k * (n - 1) - sum);
	}
	
	return 0;
}

D. Radio Towers

最近一直在写思维题,也就是cf前几题

现在终于写了一道涉及到一些算法的题目了

这题中学到了很多

(1)首先要观察出一个递推关系。新加的村庄可以和前面的答案产生联系

把最后一个村覆盖到,剩下的部分就是前面的答案

于是有Fn = Fn-1 + Fn-3 + Fn-5……

看到这我以为要把以前的答案都搜一遍

然后后来发现这个式子可以再化简

Fn-3 + Fn-5…… = Fn-2

于是Fn = Fn-1 + Fn-2 这不就是斐波那契数列么

其实这种题一开始列前几项的分子就可以找一下规律,发现是斐波那契数列了

因此答案就是Fn / 2^n

(2)这道题涉及到MOD,又有除法,于是要用逆元

给的MOD是个质数,又于2^n互质

于是用费马小定理,y的逆元就是y^(MOD - 2)

然后官方题解建议涉及到MOD时可以另写函数

这里只有乘法可能爆int,所以可以全部设为int,乘法时多乘一个1ll

加法乘法可以都写个函数,就不用总是写个%MOD

(3)逆元一般就会涉及到快速幂。复习一下快速幂

cf题写完后一定要看官方题解和代码,学习一下,收获很大

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)  
using namespace std;

const int MOD = 998244353;
const int MAXN = 2e5 + 10;
int f[MAXN];

int add(int a, int b) { return (a + b) % MOD; };
int mul(int a, int b) { return 1ll * a * b % MOD; }

int binpow(int a, int b)
{
	int res = 1;
	while(b)
	{
		if(b & 1) res = mul(res, a);
		a = mul(a, a);
		b >>= 1;
	}
	return res;
}

int main()
{
	int n; scanf("%d", &n);
	f[1] = f[2] = 1;
	_for(i, 3, n)
		f[i] = add(f[i-1], f[i-2]);
	printf("%d\n", mul(f[n], binpow(binpow(2, n), MOD - 2)));
	return 0;
}

 

决定好了

以后只用周三晚上和周五下午晚上来一次性解决作业

其他时候晚自习(自己来自习室)刷题

考前两周复习保证绩点

大计思修用来刷题

支撑我的一定是热爱,是内在驱动力

 

Codeforces Round #684 (Div. 2)

今晚来了一场模拟比赛,是赛前第五套题。以后晚上有空都可以来一次比赛加补题

今晚ac了3题,还不错吧。这是第二次模拟比赛。第一次ac了两题,有进步

 

A. Buy the String

比赛有点紧张过度了,导致a题中间有个字母打错了卡了一会儿

打完后可以检查一遍代码,不要太着急

精力集中且井然有序

赛后看题解发现还可以简化,只有换和不换两种可能

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++) 
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		int n, c0, c1, h;
		scanf("%d%d%d%d", &n, &c0, &c1, &h);
		
		int ans = 0;
		if(c0 > c1)
		{
			_for(i, 1, n)
			{
				int x; scanf("%1d", &x);
				if(x == 1) ans += c1;
				else ans += min(c0, c1 + h);
			}
		}
		else
		{
			_for(i, 1, n)
			{
				int x; scanf("%1d", &x);
				if(x == 0) ans += c0;
				else ans += min(c1, c0 + h);
			}
		}
		
		printf("%d\n", ans);
	}
	
	return 0;	
} 

 

B. Sum of Medians

这题我是看样例选的数猜出算法的

发现样例选的中位数在数列中的间隔都一样

然后发现显然是贪心

用上了下午刚学的向上取整

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++) 
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 2e5 + 10;
int a[MAXN];

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		int n, k;
		scanf("%d%d", &n, &k);
		_for(i, 1, n * k) scanf("%d", &a[i]);
		
		long long ans = 0;
		int t = n - (n + 1) / 2;
		int p = n * k - t;
		
		int cnt = k;
		while(cnt--) ans += a[p], p -= t + 1;
		printf("%lld\n", ans);
	}
	
	return 0;	
} 

 

C1. Binary Table (Easy Version)

一开始毫无思路

突然想到可以每一个2乘2的矩阵的暴力变成0

然后就对2乘2矩阵的每一种情况分类讨论,看似多,其实可以相互转化,最后并不是很多,拿笔演算

这题码量挺大,我中间还有点迷要不要继续写,坚持写下去最后ac了,不错不错

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++) 
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
#define search 	_for(i, x, x + 1) _for(j, y, y + 1)
using namespace std;

const int MAXN = 110;
const int MAXM = 6e4 + 10;
int a[MAXN][MAXN], n, m, cnt;
vector<int> ans[MAXM];

void add_ans(int x, int y, int xx, int yy) 
{
	cnt++; ans[cnt].clear();
    search
		if(i != xx || j != yy)
		{
			a[i][j] ^= 1;
			ans[cnt].push_back(i);
			ans[cnt].push_back(j);
		}
}

void deal3(int x, int y)
{
	search
		if(!a[i][j]) 
		{
			add_ans(x, y, i, j);
			return;
		}	
}

void deal2(int x, int y)
{
	int x1 = 0, y1, x2, y2;
	search
		if(a[i][j]) 
		{
			if(!x1) x1 = i, y1 = j;
			else x2 = i, y2 = j;
		}	
			
	int flag = abs(x1 - x2) + abs(y1 - y2);
	search
		if((flag == 1 && !a[i][j]) || (flag == 2 && a[i][j]))
		{
			add_ans(x, y, ((i-x)^1)+x, ((j-y)^1)+y);
			deal3(x, y);
			return;
		}
}

void deal1(int x, int y)
{
	search
		if(a[i][j]) 
		{
			add_ans(x, y, ((i-x)^1)+x, ((j-y)^1)+y);
			deal2(x, y);
			return;
		}	
}

void deal4(int x, int y)
{
	add_ans(x, y, x, y);
	deal1(x, y);
}

int count(int x, int y)
{
	int res = 0;
	search
		res += a[i][j];
	return res;
}

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		cnt = 0;
		scanf("%d%d", &n, &m);
		_for(i, 1, n)
			_for(j, 1, m)
				scanf("%1d", &a[i][j]);
		
		_for(i, 1, n - 1)
			_for(j, 1, m - 1)
			{
				int num = count(i, j);
				if(num == 1) deal1(i, j);
				if(num == 2) deal2(i, j);
				if(num == 3) deal3(i, j);
				if(num == 4) deal4(i, j);
			}
		
		printf("%d\n", cnt);
		_for(i, 1, cnt)
		{
			REP(j, 0, 6)
				printf("%d ", ans[i][j]);
			puts("");
		}
	}
	
	return 0;	
} 

C2. Binary Table (Hard Version)

赛后补题

看了题解,没我想的那么难。

必须要少于nm个操作,其实暗含着提示

也就是每次操作至少去掉一个1

于是我们可以一行一行的去,一列一列的去

从最下面一行开始,遍历一遍,有1就把它去掉,去完行数减一

最后剩下2乘2

就可以用我之前easy version的方法(用笔手算出多种情况)

其实不难,但我当时就是没想到这个思路

我想不到是因为三个同时变化太复杂了,有多种可能

而这种思路就是把三个变化化成一个变化,大大简化

同时把全部变为0转化为一行一行为0,也简化了

把二维问题简化成一维问题

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++) 
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
#define search 	_for(i, x, x + 1) _for(j, y, y + 1)
using namespace std;

const int MAXN = 110;
const int MAXM = 6e4 + 10;
int a[MAXN][MAXN], n, m, cnt;
vector<int> ans[MAXM];

void add_ans(int x, int y, int xx, int yy) 
{
	cnt++; ans[cnt].clear();
    search
		if(i != xx || j != yy)
		{
			a[i][j] ^= 1;
			ans[cnt].push_back(i);
			ans[cnt].push_back(j);
		}
}

void deal3(int x, int y)
{
	search
		if(!a[i][j]) 
		{
			add_ans(x, y, i, j);
			return;
		}	
}

void deal2(int x, int y)
{
	int x1 = 0, y1, x2, y2;
	search
		if(a[i][j]) 
		{
			if(!x1) x1 = i, y1 = j;
			else x2 = i, y2 = j;
		}	
			
	int flag = abs(x1 - x2) + abs(y1 - y2);
	search
		if((flag == 1 && !a[i][j]) || (flag == 2 && a[i][j]))
		{
			add_ans(x, y, ((i-x)^1)+x, ((j-y)^1)+y);
			deal3(x, y);
			return;
		}
}

void deal1(int x, int y)
{
	search
		if(a[i][j]) 
		{
			add_ans(x, y, ((i-x)^1)+x, ((j-y)^1)+y);
			deal2(x, y);
			return;
		}	
}

void deal4(int x, int y)
{
	add_ans(x, y, x, y);
	deal1(x, y);
}

int count(int x, int y)
{
	int res = 0;
	search
		res += a[i][j];
	return res;
}

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		cnt = 0;
		scanf("%d%d", &n, &m);
		_for(i, 1, n)
			_for(j, 1, m)
				scanf("%1d", &a[i][j]);
				
		while(n > 2)
		{
			_for(j, 1, m - 1)
				if(a[n][j])
					add_ans(n - 1, j, n, j + 1);
			if(a[n][m]) add_ans(n - 1, m - 1, n, m - 1);
			n--;	
		}	
		
		while(m > 2)
		{
			_for(i, 1, n - 1)
				if(a[i][m])
					add_ans(i, m - 1, i + 1, m);
			if(a[n][m]) add_ans(n - 1, m - 1, n - 1, m);
			m--;	
		}	
		
		int num = count(1, 1);
		if(num == 1) deal1(1, 1);
		if(num == 2) deal2(1, 1);
		if(num == 3) deal3(1, 1);
		if(num == 4) deal4(1, 1);
		
		printf("%d\n", cnt);
		_for(i, 1, cnt)
		{
			REP(j, 0, 6)
				printf("%d ", ans[i][j]);
			puts("");
		}
	}
	
	return 0;	
} 

 

12.16 周三

Codeforces Round #682 (Div. 2)

赛前第6套cf题

上午打了模拟比赛

这次我太水了,只过了a题,bc题硬是没想出来

还很菜,认真补题

 

A. Specific Tastes of Andre

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		int n; scanf("%d", &n);
		_for(i, 1, n) printf("1 ");
		puts("");
	}
	return 0;
}

B. Valerii Against Everyone

其实思路很简单,可我就是没想到

一开始想到二进制,一堆一堆数不好比较,也不知道怎么遍历

看了题解发现原来可以字串长度就为1,看有没有相同元素就可以了

先想到如果序列长度为1时,两个相等就可以

再想如不存在时,那么一定不行

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

map<int, bool> vis;

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		vis.clear();
		int ans = 0;
		int n; scanf("%d", &n);
		
		_for(i, 1, n) 
		{
			int x; scanf("%d", &x);
			if(!vis[x]) vis[x] = 1;
			else ans = 1;
		}
		
		if(ans) puts("YES");
		else puts("NO");
	}
	
	return 0;
}

 

C. Engineer Artem

受昨天矩阵的一题影响,想一行一行地处理或者一列一列的处理

发现比较麻烦,因为这里一行处理完之后并不能完全扔掉,思维很复杂

题解很骚,处理成棋盘,每个相邻的都是一奇一偶

这思路太清奇了

只能说我做的题还太少吧

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 110;
int a[MAXN][MAXN], n, m;

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		scanf("%d%d", &n, &m);
		_for(i, 1, n)
			_for(j, 1, m)
			{
				scanf("%d", &a[i][j]);
				if((i + j) & 1)
				{
					if((a[i][j] & 1)  == 0) a[i][j]++;
				}
				else 
				{
					if(a[i][j] & 1) a[i][j]++;
				}
			}
				
		_for(i, 1, n)
		{
			_for(j, 1, m)
				printf("%d ", a[i][j]);
			puts("");
		}
	}
	
	return 0;
}

 

课内的oj题和作业可以集中时间一起做,其他时间留出整块的时间编程

另外题目可以存在脑子里想思路,有空就想,想通了ac就是写个程序的事情

 

最近调整时间管理方式,真的多了很多时间来刷oj,太爽了

保持这种时间分配的方式

 

Codeforces Round #683 (Div. 2, by Meet IT)

今天晚上来一套。这是赛前第七套了。独立做出abcd,爽

A. Add Candies

只有相对关系有用,关注差值就好

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		int n; scanf("%d", &n);
		printf("%d\n", n);
		_for(i, 1, n) printf("%d ", i);
		puts("");
	}
	return 0;
}

B. Numbers Box

发现一个负号可以随意传递

所以分奇数个负号和偶数个负号就行 可以发现0不影响答案

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 15;
int a[MAXN][MAXN], n, m;

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		int sum = 0, cnt = 0, mi = 1e9;
		
		scanf("%d%d", &n, &m);
		_for(i, 1, n)
			_for(j, 1, m)
			{
				scanf("%d", &a[i][j]);
				if(a[i][j] < 0) cnt++;
				mi = min(mi, abs(a[i][j]));
				sum += abs(a[i][j]);
			}
		
		if(cnt & 1) printf("%d\n", sum - mi * 2);
		else printf("%d\n", sum);
	}
	
	return 0;	
} 

C. Knapsack

看完以为01背包,然后发现体积可以到10的18次方,肯定不能背包

不存在一个物品就可以的情况下

把小于一半体积的物品求和就行,只要大于一半体积说明肯定可以

我这里输入到一半break了,wa了几次

以后要注意,退出时输入要输入完

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

typedef long long ll;
const int MAXN = 2e5 + 10;
ll w, key;
int a[MAXN], n, m;

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		scanf("%d%lld", &n, &w);
		key = (w + 1) / 2;
		
		m = 0; int t;
		_for(i, 1, n) 
		{
			scanf("%d", &a[i]);
			if(key <= a[i] && a[i] <= w)
			{
				m = 1;
				t = i;
			}
		}
		
		if(m) 
		{
			printf("%d\n%d\n", m, t);
			continue;
		}
		
		ll sum = 0;
		int flag = 0;
		
		_for(i, 1, n)
			if(a[i] < key)
			{
				sum += a[i];
				m++;
				if(sum >= key)
				{
					flag = 1;
					break;
				}
			}
		
		if(!flag) puts("-1");
		else
		{
			printf("%d\n", m);
			_for(i, 1, n)
				if(a[i] < key)
				{
					printf("%d ", i);
					if(--m == 0) break;
				}
		}	
	}
	
	return 0;	
} 

D. Catching Cheaters

D题终于涉及到点算法了

一开始挺懵逼的

然后发现题目那个式子可以化简

其实就是每个串相同的个数减去不同的个数

那么dp就完事,从之前最长公共子序列的dp拓展开就好

可以说是最长公共子序列的拓展变形

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 5000 + 10;
int f[MAXN][MAXN], n, m;
char a[MAXN], b[MAXN];

int main()
{
	scanf("%d%d", &n, &m);
	scanf("%s%s", a + 1, b + 1);
	
	int ans = 0;
	_for(i, 1, n)
		_for(j, 1, m)
		{
			if(a[i] == b[j]) f[i][j] = max(f[i-1][j-1], 0) + 2;
			else f[i][j] = max(max(f[i-1][j], f[i][j-1]), 0) - 1;
			ans = max(ans, f[i][j]);
		}
	printf("%d\n", ans);
	
	return 0;	
} 

12.17 周四

其实目前D题对我来说也没有多难。今天可以多做一些D题

D. Circle Game

看了题感觉是y=x这条线一直走,但不知道怎么证明

ac后看题解,题解也没说为什么

我的写法比官方题解好一些,不需要枚举,可以直接算出来,开根号

注意pow的结果是double,double可以很大,但会损失精度

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
 
int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
    	int d, k;
    	scanf("%d%d", &d, &k);
    	
    	int n = sqrt(pow(d, 2) / (2 * pow(k, 2)));
    	if(pow(n * k, 2) + pow(n * k + k, 2) > pow(d, 2)) puts("Utkarsh");
    	else puts("Ashish");
	}
	
    return 0;
}

D. Sequence and Swaps

这题其实思路蛮快的,但后来一直WA

突然发现是要额外判断一下数据相等的情况

这个时候这片数据的中间部分就不要交换了,我多算了这一块

写了个O(n)的算法,应该是比官方题解的n要优的(我完全没想到dp)

我找到问题补上了一个循环,以为复杂度变成了n方

其实算了一下不是,依然是n

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++) 
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 500 + 10;
int a[MAXN], n, x;

int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		scanf("%d%d", &n, &x);
		_for(i, 1, n) scanf("%d", &a[i]);

		int ans = 0, p = 1;
		_for(i, 1, n - 1)
		{
			if(a[i] <= a[i+1]) continue;
			
			int flag = 1;
			_for(j, p, i)
			{
				if(a[j] > x)
				{
					p = j;
					break;
				}
				if(j == i) flag = 0;
			}
			
			if(!flag) { ans = -1; break; }
			
			if((p == i && x <= a[i+1]) || (p != i && a[i-1] <= a[i+1]))
			{
				ans += i - p + 1;
				_for(j, p, i - 1)
					if(a[j] == a[j+1])
						ans--;
				x = a[i];
				p = i + 1; 
			}
			else { ans = -1; break; }
		}
		
		printf("%d\n", ans);
	}
	
	return 0;
} 

D. Divide and Summarize

又刚一道,发现只是简单搜索而已

可以发现原来的顺序是没有关系的,所以一开始可以排个序

然后搜索就完事了

用到了unordered_map 如果只需要查找就可以用这个,比map要快。内部是哈希表,每次O(1)

然后搜索中间我还用了个二分和前缀和

然而我发现并没有优化多少,和直接遍历一遍效果差不多。算一下直接遍历就是nlogn,其实已经可以了

还要注意最大值最小值相同的情况,要额外处理一下,不然会一直递归。注意递归出口,写递归先考虑出口

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++) 
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
 
typedef long long ll;
const int MAXN = 1e5 + 10;
unordered_map<int, bool> vis;
int a[MAXN], n, q;
ll s[MAXN];
 
void dfs(int l, int r)
{
	ll sum = s[r] - s[l-1];
	if(sum <= 1e9) vis[sum] = 1;
	if(l == r) return;
	int mid = upper_bound(a + l, a + r + 1, (a[l] + a[r]) >> 1) - a - 1;
	if(mid == r) return;
	dfs(l, mid); dfs(mid + 1, r);
}
 
int main()
{
	int T; scanf("%d", &T);
	while(T--)
	{
		scanf("%d%d", &n, &q);
		_for(i, 1, n) scanf("%d", &a[i]);
		sort(a + 1, a + n + 1);
		_for(i, 1, n) s[i] = s[i-1] + a[i];
		
		vis.clear(); 
		dfs(1, n);
		
		while(q--)
		{
			int x; scanf("%d", &x);
			if(vis[x]) puts("Yes");
			else puts("No");
		}
	}
	
	return 0;
} 

D. XOR-gun

想了一个半小时,没想出来。

但思考的过程中收获还是很多的

(1)了解了异或的交换律结合律,自反性

利用自反性可以写出类似前缀和的东西

(2)简化思维

我有时候会把问题想复杂

比如这道题,要不符合其实就是存在一个a > b

那就找这个就行了

 

看了题解感觉太骚了

从每个数的最高位考虑,思考符合条件的特殊情况

如果不符合,发现这个时候n就会变得很小,60左右,

那这时就不用考虑复杂度什么的了

这个思路完全想不到,还是做题太少

先考虑特殊情况,才考虑除特殊情况外的其他情况

#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++) 
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;

const int MAXN = 2e5 + 10;
int a[MAXN], b[MAXN], s[MAXN], n;

int f(int n)
{
	int res = 0;
	while(n)
	{
		res++;
		n >>= 1;
	}
	return res;
}

int get(int l, int r)
{
	return s[r] ^ s[l-1];
}
 
int main()
{
	scanf("%d", &n);
	_for(i, 1, n) 
	{
		scanf("%d", &a[i]);
		b[i] = f(a[i]);
		s[i] = s[i-1] ^ a[i];
	}
	
	_for(i, 2, n - 1)
		if(b[i-1] == b[i] && b[i] == b[i+1])
		{
			puts("1");
			return 0;
		}
	
	
	int ans = 1e9;
	_for(l, 1, n - 1)
		_for(r, l + 1, n)
			_for(m, l, r - 1)
				if(get(l, m) > get(m + 1, r))
					ans = min(ans, r - l - 1);
	
	printf("%d\n", ans == 1e9 ? -1 : ans);

	return 0;
} 

 

周五休息,周六日打校赛了

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很高兴听到你正在学习《机器学习》这本经典的教材,下面我为你提供第十四章概率图模型的Python实现学习笔记。 ## 1. 朴素贝叶斯分类器 ### 1.1 数据准备 在本章中,我们将使用著名的鸢尾花数据集进行分类。首先,我们可以从sklearn库中导入该数据集。 ```python from sklearn.datasets import load_iris iris = load_iris() X = iris.data y = iris.target ``` ### 1.2 朴素贝叶斯分类器实现 接下来,我们可以使用sklearn库中的朴素贝叶斯分类器进行分类,具体实现如下: ```python from sklearn.naive_bayes import GaussianNB from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) gnb = GaussianNB() gnb.fit(X_train, y_train) y_pred = gnb.predict(X_test) accuracy = accuracy_score(y_test, y_pred) print('Accuracy:', accuracy) ``` ### 1.3 结果分析 运行上述代码后,我们可以得到该模型在测试集上的准确率,结果如下所示: ``` Accuracy: 1.0 ``` 可以看出,该模型在鸢尾花数据集上表现出色,准确率达到了100%。 ## 2. 隐马尔可夫模型 ### 2.1 数据准备 在本节中,我们将使用一个简单的例子来介绍隐马尔可夫模型的实现。假设我们有一个长度为100的序列,每个位置上的值都是0或1,其中0和1出现的概率分别为0.6和0.4。我们可以使用numpy库生成这个序列。 ```python import numpy as np np.random.seed(42) sequence = np.random.choice([0, 1], size=100, p=[0.6, 0.4]) ``` ### 2.2 隐马尔可夫模型实现 接下来,我们可以使用hmmlearn库中的隐马尔可夫模型进行序列建模,具体实现如下: ```python from hmmlearn import hmm model = hmm.MultinomialHMM(n_components=2) model.fit(sequence.reshape(-1, 1)) logprob, states = model.decode(sequence.reshape(-1, 1)) print('Sequence:', sequence) print('States:', states) ``` ### 2.3 结果分析 运行上述代码后,我们可以得到该模型对序列的建模结果,结果如下所示: ``` Sequence: [0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] States: [1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1] ``` 可以看出,模型对序列进行了建模,并输出了每个位置上的状态,其中0表示“假”,1表示“真”。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值