week5

第一题 光棍

题面http://oj.daimayuan.top/problem/676
实际上就是用n个1除x,算出n和除数,最开始想不会要写高精,后面发现只用除法,就可以用个res和x直接模拟手算不用高精存进字符串

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
int main() {
	int x;
	scanf("%d", &x);
	int n = 1;
	int res = 1;
	while (res < x) {
		n++;
		res *= 10;
		res++;
	}
	while (true)
	{
		while (res < x) {
			printf("0");
			n++;
			res *= 10;
			res++;
		}
		printf("%d", res / x);
		if (res % x == 0) {
			//n++;
			break;
		}
		else {
			n++;
			res = res - res / x * x;
			res *= 10;
			res++;
		}
	}
	printf(" %d",n);
}

逻辑重新理了下,发现res直接更新成对x取余就行,原本还要判断res会不会比x小导致要商0,再补1

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
int main() {
	int x;
	scanf("%d", &x);
	int n = 1;
	int res = 1;
	while (res < x) {
		n++;
		res *= 10;
		res++;
	}
	while (true)
	{
		printf("%d", res / x);
		res %= x;
		if (res == 0)break;
		res *= 10;
		res++;
		n++;
	}
	printf(" %d",n);
}

第二题 碰撞2

题面 http://oj.daimayuan.top/problem/705
按照行坐标存map,然后判断每行会不会撞就行
易得,当上一个向右,现在的向左才会装,所以写个last判相乘为不为负且上一个向右就行

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
struct node
{
	int x; int y;
};
node ori[maxn];
int main() {
	map<int, map<int, int>> mymap;
	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		int x, y;
		scanf("%d%d", &x, &y);
		node temp;
		temp.x = x;
		temp.y = y;
		ori[i] = temp;
	}
	char head[maxn];
	scanf("%s", head);
	for (int i = 0; i < n; i++) {
		if (head[i] == 'R') {
			mymap[ori[i].y][ori[i].x] = 1;
		}
		else {
			mymap[ori[i].y][ori[i].x] = -1;
		}
	}
	for (map<int, map<int, int>>::iterator it1 = mymap.begin(); it1 != mymap.end(); it1++) {
		if (it1->second.size() == 1) {
			continue;
		}
		int yes = 0;
		for (map<int, int>::iterator it2 = it1->second.begin(); it2 != it1->second.end(); it2++) {
			if (yes * it2->second == -1&&yes==1) {
				printf("Yes");
				return 0;
			}
			yes = it2->second;
		}
		//if (yes != it1->second.size() && (0 - yes) != it1->second.size()) {
		//	if (it1->second.begin()->second != -1&&yes!= it1->second.size()-1) {
		//		printf("Yes");
		//		return 0;
		//	}
	
		//}
	}
	printf("No");
}

第三题 优美!最长上升子序列

题面:http://oj.daimayuan.top/problem/671
常规方法是枚举1到i有没有比i小的数,取最长dp,但这里时间复杂度过不了,只能换种思路
i还是从1到n开始遍历,但是是从i往后更新,而不是从0到i找最大更新i,
首先,i的所有倍数都能整除i,所以j=i*2,j<=n;j+=i;
j下标对应的ori都是能取得,之后只要ori[j]>ori[i]就更新就行了,

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
int ori[maxn];
int dp[maxn];
int main() {
	int t;
	scanf("%d", &t);
	while (t--)
	{
		int n;

		scanf("%d", &n);
		for (int i = 1; i <= n; i++) {
			scanf("%d", &ori[i]);
            dp[i]=1;
		}
		for (int i = 1; i <= n; i++) {
			//int temp = 0;
			for (int j = i * 2; j <= n;j+=i) {
				if (ori[j] > ori[i]) {
					dp[j] = max(dp[i] + 1, dp[j]);
				}
			}
		}
		printf("%d\n", *max_element(dp + 1, dp + 1 + n));
	}
}

第四题 巨大的牛棚

题面:
居然是个二维dp,幸好我没傻乎乎的写bfs摁搞,那样必超时
dp,dp[i][j]表示包含(i,j)的最大面积
然后若他左,左上,上三个的面积一样,那它就等于期中之一加1,若不等,就取期中最小加1,dp[i][j]实际上也代表以这个点为右下角,有多大的面积是空的

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3+10;
int ori[maxn][maxn];
int dp[maxn][maxn];
int main() {
	int n;
	int t;
	scanf("%d%d", &n, &t);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			dp[i][j] = 1;
		}
	}
	for (int i = 0; i < t; i++) {
		int x, y;
		scanf("%d%d", &x, &y);
		dp[x][y] = 0;
	}
	int maxn = -1;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			if (dp[i][j] == 0)continue;
			//if (dp[i - 1][j] == dp[i - 1][j - 1] && dp[i][j - 1] == dp[i - 1][j]) {
			//	dp[i][j] = dp[i - 1][j] + 1;
			//}
			//else {
			//	dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;
			//}
			dp[i][j] = min(min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
			maxn = max(maxn, dp[i][j]);
		}
	}
	cout << maxn;
}

第五题 高利贷

题面:http://oj.daimayuan.top/course/11/problem/708
列了个求和公式就,
m/n=p/(1+p)^k求和
本来想直接解通项的,但太麻烦了,于是二分走起

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
double n, m, k;
double sum(double p) {
	double summ = 0;
	for (int i = 1; i <= k; i++) {
		summ += m / (pow(1.0 + p, i));
	}
	return summ;
}
int main() {

	scanf("%lf%lf%lf", &n, &m, &k);
	double l = 0, r = 1;
	while ( r-l>(1e-6))
	{
		double mid = (l + r) / 2;
		if (sum(mid) > n) {
			l = mid;
		}
		else {
			r = mid;
		}
	}
	printf("%lf", l);
}

第六题 背包

题面http://oj.daimayuan.top/course/11/problem/710

1.将所有物品从小到大排序,且大于M的直接舍弃
	1.最小的数大于w/2,YES
	2.最小的数小于w/2
		1.所有数累加小于w NO
		2.累加存在大于w/2 YES
			这种情况证明
			假设前面和为x(x<w/2),加下一个数Y后总和大于w/2
			若总和<w,YES
			若总和>w
因为Y<w,所以y+x>w,x<w/2,可证出Y>w/2,即得证YES
然后要注意下整形除法囤小数的问题
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5;
int main() {
	int t;
	cin >> t;
	while (t--)
	{
		int len = 0;
		int ori[maxn];
		long long w;
		int n;
		cin >> n >> w;
		for (int i = 0; i < n; i++) {
			int temp;
			cin >> temp;
			if (temp > w)continue;
			ori[len++] = temp;
		}
		sort(ori, ori + len);
		long long sum = 0;
		for (int i = 0; i < len; i++) {
			sum += ori[i];
			if (sum >= (w / 2+w%2)) {
				cout << "YES" << endl;
				break;
			}
		}
		if (sum < (w / 2+w%2)) {
			cout << "NO" << endl;
		}
	}
}

第七题 三回文序列

题面http://oj.daimayuan.top/course/11/problem/711
112232111为例,最开始想的是求出每个数出现的前缀合
121213345,之后遍历一遍假设现在遍历到第三个1,往前找1,并且记录这期间最长的其他数字(前缀和直接减),但是发现这个情况过不了11133333112232111,我们要的是头尾两个1,但之前的方法找到连着两个1的就停了,除非继续遍历到头,
后面改了改,
numo为每个数字前缀和,方便取出特定区间某个数的个数,先想得是外侧遍历a是几(记为i),内层遍历两边a的个数j,从1到a的个数的一半,但这个方法找符合j长度的区间起始点s和e很慢,每次都要从头开始找符合长度的,超时,后面发现不用每次都要找s和e,直接两边长度+=2,之后找下一个=i的两边就行了

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int numo[maxn][27];
int ori[maxn];
int main() {
	int t;
	scanf("%d", &t);
	while (t--)
	{
		int n;
		int num[27] = { 0 };
		//int last[27] = { 0 };
		scanf("%d", &n);
		for (int i = 0; i < n; i++) {
			scanf("%d", &ori[i]);
			num[ori[i]]++;
			numo[i][ori[i]]++;
			for (int j = 1; j <= 26; j++) {
				numo[i + 1][j] = numo[i][j];
			}

		}
		int maxo = 1;
		for (int i = 1; i <= 26; i++) {
			if (num[i] == 0)continue;
			//for (int j = 1; j <= num[i] / 2; j++) {
			//	int s;
			//	//int last;
			//	//for (int k = n-1; k >= 0; k--) {
			//	//	if (ori[k] == i) {
			//	//		s = k;
			//	//		break;
			//	//	}
			//	//}
			//	//for (int k = s; k >= 0; k--) {
			//	//	if (ori[k] != i)continue;
			//	//	if (numo[s][i] - numo[k][i] == j) {
			//	//		s = last;
			//	//		break;
			//	//	}
			//	//	last = k;
			//	//}
			//	for (int k = n - 1; k >= 0; k--) {
			//		if (numo[n - 1][i] - numo[k][i] == j) {
			//			s = k + 1;
			//			break;
			//		}
			//	}
			//	int e = 0;
			//	/*for (int k = e; k < n; k++) {
			//		if (ori[k] == i) {
			//			e = k;
			//			break;
			//		}
			//	}
			//	for (int k = e; k <n; k++) {
			//		if (ori[k] != i)continue;
			//		if (numo[k][i] - numo[e][i] == j) {
			//			e = last;
			//			break;
			//		}
			//		last = k;
			//	}*/
			//	for (int k = 0; k < n; k++) {
			//		if (numo[k][i] - 0 == j) {
			//			e = k;
			//			break;
			//		}
			//	}
			//	for (int k = 0; k <= 26; k++) {
			//		maxo = max(maxo, numo[s - 1][k] - numo[e][k] + j * 2);
			//	}
			//}
			int s = 0, e = n - 1;
			int liangbian = 0;
			while (s < e)
			{
				while (ori[s] != i)
				{
					s++;
				}
				while (ori[e] != i)
				{
					e--;
				}
				if (s >= e) {
					break;
				}
				liangbian += 2;
				for (int k = 0; k <= 26; k++) {
					maxo = max(maxo, numo[e - 1][k] - numo[s][k] + liangbian);
				}
				s++;
				e--;
			}


		}
		//maxo = max(maxo, *max_element(num+1, num + 27));
		printf("%d\n", maxo);
	}
}

第八题 简单的异或问题

题面http://oj.daimayuan.top/course/11/problem/732
咋一看挺难仔细一分析,实际上不难,首先给的范围是偶数个,因为含0,之后算几个数,其一是偶数开头,相邻两个数异或,4,5和6,7,你会发现所有2n和2n+1的数异或都等于1,1和1异或等于0。于是我们分析
0123456789.。。。。两两一组,共用2^m/2组,除掉含n的那一组,其他组异或完只有0和1两种可能
若为0,他只能和含n那一组的n异或,若为1,只能和含n的那一组的另一个数异或,这个是有另一个规律a^b=a+b得到的,所以共有2m-1种
一些特例
n=1,m=1,ans=2
n=0,m=1,ans=1;
若n=0,其他组异或完为1,即可和1异或,也可和0异或,所以要+1,又因为范围为偶数个,全部异或完必为1,所以n=0就要++。4

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
	ll n, m;
	scanf("%lld%lld", &n, &m);
	ll ans = pow(2, m);
	ans--;
	if (n == 0)ans++;
	if (n == 0 && m == 1)ans = 1;
	if (n == 1 && m == 1)ans = 2;
	printf("%lld", ans);

}

第九题 子串的循环挪动

题面:http://oj.daimayuan.top/course/11/problem/734
纯纯模拟题,把k%=(r-l+1)去掉重复旋转的情况减减复杂度就行

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
	char str[10010];
	scanf("%s", &str);
	int len = strlen(str);
	int ori[10010];
	for (int i = 1; i <= len; i++) {
		ori[i] = i;
	}
	int n;
	scanf("%d", &n);
	while (n--)
	{
		int l, r, k;
		scanf("%d%d%d", &l, &r, &k);
		int lennow = r - l + 1;
		k %= lennow;
		if (k == 0)continue;
		int temp[10010];
		int templen = 0;
		for (int i = l; i <= r; i++) {
			temp[templen++] = ori[i];
		}
		for (int i = 0; i <k; i++) {
			ori[l+i] = ori[r-(k-i-1)];
		}
		for (int i = 0; i < lennow - k; i++) {
			ori[l + i + k] = temp[i];
		}
	}
	for (int i = 1; i <= len; i++) {
		printf("%c", str[ori[i] - 1]);
	}
}

第十题 弗拉德和糖果 II

题面http://oj.daimayuan.top/problem/677
算博弈论吧,我们需要知道最多的糖果数maxn和去掉这个的所有的糖果数sum
最极限的情况是maxn==sum+1
这种12121213131314151,其他糖果一字排开,在多一个1无论如何也不行
另一种极限情况是所有种类相等
123123123
至于其他情况都符合,你可以把多出来的其他糖果插进其他不同的糖果里,因为我们规定了最多的糖果是maxn,所以不纯在不够插的情况。

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
	int n;
	scanf("%d", &n);
	ll temp, sum=0,maxn=0;
	for (int i = 0; i < n; i++) {
		scanf("%lld", &temp);
		sum += temp;
		maxn = max(temp, maxn);
	}
	sum -= maxn;
	if (maxn <= sum + 1) {
		printf("YES");
	}
	else {
		printf("NO");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值