PAT 520 钻石争霸赛 2021(100)

总结

5、7题没AC。
前4题简单,10min内搞定。第五题卡了25min没AC。6题11min较简单,不熟悉顺序表的插入删除操作。8题12min,简单板子题。7题7min到时间了,10min过的样例。5题卡了25min,差1分。
#大勾股定理

7-5 大勾股定理

25min 14/15

题意

给定数字n,总能找到一个等式形式如下: s 2 + . . . + ( s + n ) 2 = ( s + n + 1 ) 2 + . . . + ( s + 2 ∗ n ) 2 s^2 +...+ (s+n)^2 = (s+n+1)^2+...+(s+2*n)^2 s2+...+(s+n)2=(s+n+1)2+...+(s+2n)2
要求找到并输出。

思路

正确思路:

  • 根据给定公式进行数学简化,找到s与n的关系。
  • 直接输出即可。
    错误思路:
  • 相当于有数列 A s = [ ( s 2 + . . . + ( s + n ) 2 ) ] − [ ( s + n + 1 ) 2 + . . . + ( s + 2 ∗ n ) 2 ] A_s = [(s^2 +...+ (s+n)^2)] - [(s+n+1)^2+...+(s+2*n)^2] As=[(s2+...+(s+n)2)][(s+n+1)2+...+(s+2n)2]
    • A s = 0 A_s = 0 As=0
    • A s + 1 = A s − s 2 + 2 ∗ ( s + n + 1 ) 2 − ( s + 2 ∗ n + 1 ) 2 A_{s+1} = A_s - s^2 + 2*(s+n+1)^2 - (s+2*n+1)^2 As+1=Ass2+2(s+n+1)2(s+2n+1)2
    • A s + 1 − A s = 4 s ( n + 1 ) + 2 ( n + 1 ) 2 − 2 ( s ( 2 n + 1 ) ) − ( 2 n + 1 ) 2 A_{s+1} - A_s= 4s(n+1)+2(n+1)^2 - 2(s(2n+1))-(2n+1)^2 As+1As=4s(n+1)+2(n+1)22(s(2n+1))(2n+1)2
      = 4sn + 4s + 2n2 + 4n + 2 -4sn - 2s - 4n2 - 4n - 1
      = 2s + 1 - 2n^2
    • A_1 = 1+…+n^2
  • 遍历找满足条件As即可.

小结

  • 能用数学方法简化的一定要先考虑用数学方法简化。
  • 开始被卡时间,想到滑动窗口,就每次s++时 − s 2 + 2 ∗ ( s + n + 1 ) 2 − ( s + 2 ∗ n + 1 ) 2 - s^2 + 2*(s+n+1)^2 - (s+2*n+1)^2 s2+2(s+n+1)2(s+2n+1)2 。但是仍然TLE。思考可能pow用多了,于是先用f数组存所有下标对应平方,但是MLE了。
  • 这时候想折个中,一半f数组,一半pow函数。这种思想是不对的,只是可以骗分,也没过14分。
  • 交卷后考虑到可以二分,算了一下时间应该会短些。

解法1 - 数学 - 待检验

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
	int n, i, j; cin>>n;
	for(i = n * (2 * n + 1), j = 1; j <= n + 1; i ++, j ++){
		printf("%lld^2", i);
		if(j != n + 1) printf(" + "); 
	}
	printf(" =\n");
	for(int j = 1; j <= n; i++, j ++){
		printf("%lld^2", i);
		if(j != n) printf(" + ");
	}
	return 0;
}

解法2 - 二分 - 待检验

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n, s, f[5000000], l, r;
int cmp(int s){
	int l = 0, r = 0;
	for(int i = s; i <= s + n; i ++)
        l += pow(i, 2);
    for(int i = s + n + 1; i <= s + 2 * n; i ++)
        r += pow(i, 2);
	if(l < r) return 1;
	else if(l > r) return 3;
	else return 2;  
}
signed main(){
    cin>>n;
    int l = 1, r = 10000000000;
    while(l <= r){
    	int m = l + r >> 1;
    	int ptr = cmp(m);
    	if(ptr == 1) l = m + 1;
    	else if(ptr == 3) r = m - 1;
    	else{
    		s = m;
    		break;
		}
	}
    for(int i = 0; i <= n; i ++){
        if(i) printf(" + ");
        printf("%d^2", i + s);
    }
    cout<<" =\n";
    for(int i = n + 1; i <= 2 * n; i ++){
        if(i != n + 1) printf(" + ");
        printf("%d^2", i + s);
    }
    return 0;
}

题目

大勾股定理是勾股定理的推广:对任何正整数 n 存在 2n+1 个连续正整数,满足前 n+1 个数的平方和等于后 n 个数的平方和。例如对于 n=1 有  3 2 + 4 2 = 5 2 3^2+4^2=5^2 32+42=52;n=2 有  1 0 2 + 1 1 2 + 1 2 2 = 1 3 2 + 1 4 2 10^2+11^2+12^2=13^2+14^2 102+112+122=132+142 等。给定 n,本题就请你找出对应的解。

输入格式:

输入在一行中给出正整数 n(≤ 1 0 4 10^4 104)。

输出格式:

分两行输出满足大勾股定理的解,格式如下:

a[0]^2 + a[1]^2 + ... + a[n]^2 =
a[n+1]^2 + ... + a[2n]^2

其中解的数列 a[0] ... a[2n] 按递增序输出。注意行首尾不得有多余空格。

输入样例:

3

输出样例:

21^2 + 22^2 + 23^2 + 24^2 =
25^2 + 26^2 + 27^2

7-7 约会大作战

7min 1/20, 10min过样例

题意

给定两组人的人员数量n、m,和询问数q。
然后给出矩阵a[n][m]b[m][n]表示两组对对方好感度分别为多少。
最后给出q组询问对,问哪几对能匹配成功。

思路

  • 记录n、m、q。矩阵存在a、b中。
  • 然后循环q次:
    • 首先判断两个人是否有人出去了,出去则匹配失败,continue
    • 记录成员前两次约会次数在cnt1[101], cnt2[101]以及对这两次进行最大值更新mp1[101], mp2[101]
    • 匹配成功则两个人出去,out1[101], out2[101]中记录。

题解 - 待检验

#include<bits/stdc++.h>
using namespace std;
int n, m, q,x, y, a[101][101], b[101][101], cnt1[101], cnt2[101], num, mp1[101], mp2[101], out1[101], out2[101];
int main(){
	cin>>n>>m>>q;
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= m; j ++)
			cin>>a[i][j];
	for(int i = 1; i <= m; i ++)
		for(int j = 1; j <= n; j ++)
			cin>>b[i][j];
	for(int i = 0; i < q; i ++){
		cin>>x>>y;
		if(out1[x] || out2[y]) continue;
		bool f = true;
		if(cnt1[x] < 2){
			f = false;
			cnt1[x]++;
			mp1[x] = max(mp1[x], a[x][y]);
		}
		if(cnt2[y] < 2){
			f = false;
			cnt2[y]++;
			mp2[y] = max(mp2[y], b[y][x]);
		}
		if(f == true){
			num ++;
			cout<<x<<' '<<y<<endl;
			out1[x] = true;
			out2[y] = true;
		}
	}
	if(num == 0) puts("PTA is my only love");
	return 0;
}

7-6 矩阵列平移

11min

思路

  • 数组存入int f[N][N]int ptr记录偏移量。
  • 将每列看做一个顺序表,遍历偶数个列,计算偏移量,向下偏移,然后对前偏移量个元素赋值为x。
    • 计算偏移量:从1-k循环。
  • 然后循环每行、每列,计算每行元素和。

解法1 - AC

#include<bits/stdc++.h>
using namespace std;
int n, k, x, f[101][101], ans[101];
int main(){
	cin>>n>>k>>x;
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= n; j ++)
			cin>>f[i][j];
	int ptr = 0;
	for(int i = 2; i <= n; i += 2){
		ptr = ptr % k + 1;
		for(int j = n; j >= ptr; j --)
			f[j][i] = f[j - ptr][i];
		for(int j = 0; j <= ptr; j ++)
			f[j][i] = x;
	}
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			cout<<f[i][j]<<' ';
			ans[i] += f[i][j];
		}
		cout<<endl;
	}
	for(int i = 1; i <= n; i ++){
		if(i - 1)cout<<' ';
		cout<<ans[i];
	}
	return 0;
}

7-8 浪漫侧影

12min

思路

  • 常规造树,额外记录树高。
  • 层序遍历。两个指针分别记录上一个弹出元素pre,和当前队列头部元素ptr。每次访问到下一层,将pre记入ansr数组对应高度的位置,将ptr记入ansl数组对应高度的位置。
  • 按序输出ansl和ansr数组即可。

题解

#include<bits/stdc++.h>
using namespace std;
int n, in[40], post[40], mh;
int ansl[40], ansr[40];
struct node{
	int k, h;
	struct node*l, *r;
};
node* mt(int il, int ir, int pl, int pr, int h){
	mh = max(mh, h);
	if(il > ir) return NULL;
	node * t = (node*)malloc(sizeof(node));
	t->k = post[pr];
	t->h = h;
	int i = il;
	while(in[i] != post[pr])i++;
	t->l = mt(il, i - 1, pl, pl + i - 1 - il, h + 1);
	t->r = mt(i + 1, ir, pl + i - il, pr - 1, h + 1);
	return t;
} 
int main(){
	cin>>n;
	for(int i = 0; i < n; i ++) cin>>in[i];
	for(int i = 0; i < n; i ++) cin>>post[i];
	node * t = mt(0, n - 1, 0, n - 1, 0);
	queue<node*> que; que.push(t);
	ansl[0] = ansr[0] = t->k;
	int th = 0;
	node * tn = t;
	while(que.size()){
		auto tar = que.front();
		if(tar->h > th){
			ansr[th] = tn->k;
			th = tar->h;
			ansl[th] = tar->k;
		}
		tn = tar;
		que.pop();
		if(tar->l) que.push(tar->l);
		if(tar->r) que.push(tar->r);
	}
	ansr[th] = tn->k;
	cout<<"R:";
	for(int i = 0; i < mh; i ++)
		printf(" %d", ansr[i]);
	puts("");
	cout<<"L:";
	for(int i = 0; i < mh; i ++)
		printf(" %d", ansl[i]);
	return 0;
}

7-1 自动编程

1min

#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
	cin>>n;
    printf("print(%d)", n);
	return 0;
}

7-2 加油冲鸭

3min

#include<bits/stdc++.h>
using namespace std;
int n, m, s, sum;
int main(){
	cin>>n>>m>>s;
    sum = n - m * s;
    if(sum <= n / 2) printf("hai sheng %d mi! chong ya!", sum);
    else printf("hai sheng %d mi! jia you ya!", sum);
	return 0;
}

7-3 520的表白

2min

#include<bits/stdc++.h>
using namespace std;
int main(){
    string r; cin>>r;
    for(int i = 0; i < 520; i ++)
        puts(r.c_str());
	return 0;
}

7-4 奇葩楼层

2min

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n, d; cin>>n>>d;
    int cnt = n;
    for(int i = 1; i <= n; i ++){
        string s = to_string(i);
        if(s.find('0' + d) != -1) cnt--;
    }
    cout<<cnt;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值