AutoX安途杯中山大学程序设计校赛(同步赛)题解

赛时过题:A C D I

赛后补题:B E G

A:

题意:给定两个数A,B求一个C,要求三个数之和是1e6的倍数,三个数字的范围都是[0, 1e6)

解题思路:首先我们要知道一个数字0倍也是它的倍数,那么如果A,B都是0的时候,C是0也可以满足;但是如果A,B不是0的时候,我们可以先用1e6去减,如果C小于0的话再添加一个1e6

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int T;
int A,B,C;
int main()
{
	cin >> T;
	while(T--)
	{
		cin >> A >> B;
		C = 1000000 - A - B;
		if(C < 0) C = 2000000 - A - B;
		if(C == 1000000) C = 0;
		cout << C<<"\n";
	}
	return 0;
}

C:

题目大意:给定一个3 * 3的矩阵,给定固定位置的三个数字,求是否能推出整个矩阵

解题思路:队友写的,通过推导方式可以求出若(6 * a + 3 * b + 3 * d) % 4不为0的时候,矩阵不存在,那么反之则存在

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <string.h>
#include <cstring>
#include <math.h>
#include <cmath>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#include <cctype>
#include <iostream>
#include <fstream>
#include <limits.h>
#include <algorithm>
#include <sstream>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <set>
#include <cstdio>
#include <list>
#define RE0 return 0;
#define pi acos(-1.0)
#define pii pair<int, int>
#define ll long long
const long long mod = (ll)(1e7 + 1e5 + 1e3 + 7);
const double eps = 1e-8;
const int inf = 0x3f3f3f3f;
const int maxN = (int)1e6 + 7;
const int modulenumber = (int)1e9 + 7;
using namespace std;
ofstream ofs;

typedef struct stu
{
	int number;
	char name[35];
	int time;
	int happy;
	bool friend operator <(stu a, stu b)
	{
		return a.happy < b.happy;
	}
}  STU;
int cmp(const void* p, const void* q)
{
	int pa = *((int*)p);
	int qa = *((int*)q);
	return qa - pa;
}
long long qpow(long long a, long long b)
{
	long long res = 1;
	while (b)
	{
		if (b & 1)
		{
			res *= a;
			res %= mod;
		}
		b >>= 1;
		a *= a;
		a %= mod;
	}
	return res;
}
int gcd(int a, int b)
{
	return b ? gcd(b, a % b) : a;
}
int Manhattan_distance(int x1, int x2, int y1, int y2)
{
	return max(x1 - x2, x2 - x1) + max(y1 - y2, y2 - y1);
}
inline int read()
{
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch>'9')
	{
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
		x = x * 10 + ch - '0', ch = getchar();
	return x * f;
}

map< int, int> cnt;
stack<int> st;
queue<int> que;
multiset<int> se;
string str;

int n, k, T, m;
int flag = 1;

int main()
{
	scanf("%d", &T);
	while (T--)
	{
		int a, b, c, d, e, f, g, h, i;
		scanf("%d%d%d", &a, &b, &d);
		if ((6 * a + 3 * b + 3 * d) % 4)
		{
			printf("-1\n");
		}
		else
		{
			int t = (6 * a + 3 * b + 3 * d) / 4;
			c = t - a - b;
			e = 2 * a + b + d - t;
			f = 2 * t - 2 * a - b - 2 * d;
			g = t - a - d;
			h = 2 * t - 2 * a - 2 * b - d;
			i = 3 * a + 2 * b + 2 * d - 2 * t;
			printf("%d %d %d %d %d %d\n", c, e, f, g, h, i);
		}
	}
	RE0
}

D

题目大意:给定一个含有x的二阶行列式,求出x的范围

解题思路:首先我们要先想到x系数是0的情况,对此拿出来进行讨论分析式子是否恒定满足;再者我们根据样例分析了负号是在分子上面的,因此我们也需要对系数和被除数进行一个处理;最后不要忘记对分子分母同时取一个最大公因式化简成最简形式

#define _CRTSECURE_nOWARnInGS
#pragma warning(disable:4996)
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <list>
using namespace std;

int t;
char s[10];
int n[10];
int pin;

int main()
{
	scanf("%d", &t);
	while (t--)
	{
		memset(n, 0, sizeof(n));
		for (int i = 1; i <= 4; i++)
		{
			int neg = 1;
			memset(s, 0, sizeof(s));
			scanf("%s", s);
			int l = strlen(s);
			if (s[0] == 'x')
			{
				pin = i;
				n[pin] = 1;
			}
			else
			{
				if (s[0] == '-') neg = -1;
				else n[i] = n[i] * 10 + s[0] - '0';
				for (int j = 1; j < l; j++)
				{
					n[i] = n[i] * 10 + s[j] - '0';
				}
				n[i] *= neg;
			}
		}
//		for(int i = 1;i <= 4;++i)
//		{
//			printf("%d ",n[i]);
//		}
//		printf("\n");
		int fmul = n[1] * n[4];
		int smul = n[2] * n[3];
		int pmul;
		int flag = 1;
		int sum = fmul + smul;
		if(pin == 1 || pin == 4)
		{
			pmul = fmul;
		}
		else pmul = smul;
		if(pmul == 0)
		{
			if(fmul > smul) printf("R\n");
			else printf("E\n");
		}
		else
		{
			if(pin == 1 || pin == 4)
			{
				if(fmul > 0)
				{
					flag = 1;
					if(smul < 0) flag = -1;
					if(smul % fmul == 0)
					{
						printf("x>%d\n",smul / fmul);
					}
					else
					{
						printf("x>%d/%d\n",flag * abs(smul / __gcd(smul,fmul)),abs(fmul / __gcd(smul,fmul)));
					}
				}
				else if(fmul < 0)
				{
					if(smul > 0) flag = -1;
					if(smul % fmul == 0)
					{
						printf("x<%d\n",smul / fmul);
					}
					else
					{
						printf("x<%d/%d\n",flag * abs(smul / __gcd(smul,fmul)),abs(fmul / __gcd(smul,fmul)));
					}
				}
			}
			else
			{
				if(smul > 0)
				{
					if(fmul < 0) flag = -1;
					if(fmul % smul == 0)
					{
						printf("x<%d\n",fmul/smul);
					}
					else
					{
						printf("x<%d/%d\n",flag * abs(fmul/__gcd(smul,fmul)),abs(pmul/__gcd(smul,fmul)));
					}
				}
				else
				{
					if(fmul > 0) flag = -1;
					if(fmul % pmul == 0)
					{
						printf("x>%d\n",fmul/pmul);
					}
					else
					{
						printf("x>%d/%d\n",flag * abs(fmul/__gcd(pmul,fmul)),abs(pmul/__gcd(pmul,fmul)));
					}
				}
			}
		}
	}
	return 0;
}

I

题目大意:给定一个数字N,我们需要找出四个数字A,B,C,D使得A * D = B * C,同时N−3sqrt(N)​<A<B<C<D<N

解题思路:我们有一个式子对于任意的(kx * (k + 1)y) = (ky * (k + 1) x)(y = x + 1)

然后我们需要找一个最大倍数K

找的过程中可以用minpos / sqrt(n)去寻找

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
int T;
ll n;
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%lld",&n);
		ld minpos = n - 3 * sqrtl(n);
		ll ans1 = sqrtl(n);
		ll ans2 = ans1+1;
		ll t = minpos / ans1;
		while(minpos >= ans1 * t)
		{
			++t;
		}
		printf("%lld %lld %lld %lld\n",ans1 * t, ans2 * t,ans1 * (t + 1), ans2 * (t + 1));
	}
	return 0;
}

E

题目大意:删除相邻的两个数字,同时补入一个数字是他们两个相减之后再取绝对值最后获得一个最小的数字

解题思路:因为数据范围很小,对于任意位置上面的数字都有两种可能,第一种是我这个位置上面的数字去减别的数字;第二种是别人来减我这个数字,对于第一种我们直接扔正数的值进去,对于第二种负数的情况我们直接扔负数的数值进去,因为数值很小,我们直接进行DFS就可以解决这个问题

后续思考:在赛时没有做出来的原因是因为没有在根据这个数字范围进行进一步的联想,没有进行一个直接的暴力,在过题人数很多的情况下我需要考虑一发很暴力的暴力

#include <bits/stdc++.h>
using namespace std;
int T;
int n,m;
int a[20];
int ans;
void dfs(int val,int id)
{
	if(id > n)
	{
		ans = min(ans,val);
		return;
	}
	dfs(abs(val + a[id]),id + 1);
	dfs(abs(val - a[id]),id + 1);
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i = 1;i <= n;++i) scanf("%d",&a[i]);
		ans = 0x3f3f3f3f;
		dfs(a[1],2);
		printf("%d\n",ans);
	}
	return 0;
}

B:

题目大意:

有一个N * N 的矩阵,我每次可以对这个矩阵进行如下操作:

1:让整个行开/关 2:让整个列开/关 3:让一个对角线开或关

解题思路:

首先我们先不考虑对角线的操作,我们先考虑行和列的操作

如果我们打开一行一列,那么实际上打开的灯的数量是 2 n - 2

根据这个我们推导出式子:n * numr + n * numc - 2 * numr * numc

再根据这个式子,我们思考如果有对角线的情况怎么办?

那么我们需要记录对角线等已经点亮了的情况,然后再在后面进行一个相减的操作

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <string.h>
#include <cstring>
#include <math.h>
#include <cmath>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#include <cctype>
#include <iostream>
#include <fstream>
#include <limits.h>
#include <algorithm>
#include <sstream>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <set>
#include <cstdio>
#include <list>
#define RE0 return 0;
#define pi acos(-1.0)
#define pii pair<int, int>
#define ll long long
const long long mod = (ll)(1e7 + 1e5 + 1e3 + 7);
const double eps = 1e-8;
const int inf = 0x3f3f3f3f;
const int maxN = (int)1e6 + 7;
const int modulenumber = (int)1e9 + 7;
using namespace std;
ofstream ofs;

typedef struct stu
{
	int number;
	char name[35];
	int time;
	int happy;
	bool friend operator <(stu a, stu b)
	{
		return a.happy < b.happy;
	}
}  STU;
int cmp(const void* p, const void* q)
{
	int pa = *((int*)p);
	int qa = *((int*)q);
	return qa - pa;
}
long long qpow(long long a, long long b)
{
	long long res = 1;
	while (b)
	{
		if (b & 1)
		{
			res *= a;
			res %= mod;
		}
		b >>= 1;
		a *= a;
		a %= mod;
	}
	return res;
}
int gcd(int a, int b)
{
	return b ? gcd(b, a % b) : a;
}
int Manhattan_distance(int x1, int x2, int y1, int y2)
{
	return max(x1 - x2, x2 - x1) + max(y1 - y2, y2 - y1);
}
inline int read()
{
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch>'9')
	{
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
		x = x * 10 + ch - '0', ch = getchar();
	return x * f;
}

map< int, int> cnt;
stack<int> st;
queue<int> que;
multiset<int> se;
string str;

int n, k, T, m;
int flag = 1;

ll col[100005] = { 0 }, row[100005] = { 0 }, dia = 0, numc = 0, numr = 0, numd = 0;

int main()
{
	scanf("%d", &T);
	while (T--)
	{
		memset(col, 0, sizeof col);
		memset(row, 0, sizeof row);
		dia = 0;
		numc = 0;
		numr = 0;
		numd = 0;
		scanf("%d %d\n", &n, &m);
		for (int i = 0; i < m; ++i)
		{
			char c;
			int t;
			scanf("%c", &c);
			while (c == '\n')
			{
				scanf("%c", &c);
			}
			if (c == 'R')
			{
				scanf("%lld", &t);
				if (row[t] == 0)
				{
					row[t] = 1;
					++numr;
					if (col[t] == 1)
					{
						++numd;
					}
				}
				else
				{
					row[t] = 0;
					--numr;
					if (col[t] == 1)
					{
						--numd;
					}
				}
			}
			if (c == 'C')
			{
				scanf("%lld", &t);
				if (col[t] == 0)
				{
					col[t] = 1;
					++numc;
					if (row[t] == 1)
					{
						++numd;
					}
				}
				else
				{
					col[t] = 0;
					--numc;
					if (row[t] == 1)
					{
						--numd;
					}
				}
			}
			if (c == 'D')
			{
				dia = 1 - dia;
			}
			if (dia == 0)
			{
				printf("%lld\n", n * numr + n * numc - 2 * numr * numc);
			}
			else
			{
				printf("%lld\n", n * numr + n * numc - 2 * numr * numc + n - 2 * (numr + numc - 2 * numd));
			}
		}
	}
	RE0
}

G

题目大意:给定n个数字,给定3个栈,如何操作我们可以使得所有数据在第一个栈中以非递减的形式存在

解题思路:我们对于给定一些数字可以进行这样一个操作,按这一个数位中是否是1然后把他放入stack2 或者stack3,因为在这一位上是1的,那么他相对这一位数值上是0的数字就要更大一些,那我们每次都进行这样的操作,并且按照栈的方式把他扔进原栈中,最后就能够排序成功,而且我们对于每个数字都是需要离散化的(只需要记录其相应的数字位置),然后对于每个数字我们最多进行操纵10次,最多肯定不会超过20000次

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
pair<int,int> p[maxn];
int ans[maxn][10];
int a[maxn];
int b[maxn];
int c[maxn];
int na,nb,nc;
int n;
int ansn;
void add(int x,int y)
{
	ans[++ansn][0] = x;
	ans[ansn][1] = y;
}
int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n;++i)
	{
        scanf("%d",&a[i]);
		p[i] = make_pair(a[i],i);
	}
	sort(p + 1,p + 1 + n);
	for(int i = 1;i <= n;++i) a[p[i].second] = i;
	for(int i = 0;i < 10;++i)
	{
		na = 0;
		nb = 0;
		nc = 0;
		for(int j = n;j >= 1;j--)
		{
			if((a[j] >> i) & 1)
			{
				b[++nb] = a[j];
				add(1,2);
			}
			else
			{
				c[++nc] = a[j];
				add(1,3);
			}
		}
		while(nb)
		{
			a[++na] = b[nb--];
			add(2,1);
		}
		while(nc) 
		{
			a[++na] = c[nc--];
			add(3,1);
		}
	}
	printf("%d\n",ansn);
	for(int i = 1;i <= ansn;++i)
	{
		printf("%d %d\n",ans[i][0],ans[i][1]);
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值