引流广西东信杯
“中国东信杯”广西大学第三届程序设计竞赛(新生组)”
https://ac.nowcoder.com/acm/contest/10172?&headNav=www#rank
密码:2020gxuacm19
公共题第一题:A++++
题解:判定na和in的最小值。
如果用char string[200]存的话就很简单了
开两个计数器,读string[0]是i或者n
然后求两个计数器的最小值。总用时八分钟,主要读歪题了
#include<iostream>
#include<stack>
#include<string>
#include<cstring>
#include<algorithm>
//这个是大整数,一般打竞赛long long不容易爆数据int
#define ll long long
#define N 100000
using namespace std;
int main(){
//关闭流同步,比赛代码,因为cin比scanf慢,会被time limited exceed
ios::sync_with_stdio(false);
ll n=0;
//等效于scanf("%lld",&n);
cin>>n;
while(n--){
ll t,count1=0,count2=0;
cin>>t;
while(t--){
char s[40];
cin>>s;
if(s[0]=='i')count1++;
if(s[0]=='n')count2++;
}
//等效printf("A");
cout<<'A';
//判定两个计数器哪个数字小,把小的打进count1
count1=min(count1,count2);
while(count1--){
cout<<'+';
}
cout<<endl;//回车不能丢
}
}
第二题:GDP Carry
博弈论,题目和题面毫无干系的题
推理一个结果。已知先手只能走奇数步,后手只能走偶数步
就可以猜测是和奇偶性有关的博弈。我们大胆讨论:
1.如果是总和是奇数,那么龙老板赢定了,因为他一次可以拿完。
2.如果总和是偶数,那么龙老板要怎么样赢呢?偶数=奇数+奇数
3.而一旦出现了奇数,那么光依靠小西肯定是不能使得剩下的步数变成偶数
也就是说,龙老板必然还可以走一步。
总结:
只要步数中有一个奇数步
那么龙老板必然可以走一步
那么小西就必然不能让龙老板在他之前停下。龙老板赢
#include<iostream>
#include<stack>
#include<string>
#include<cstring>
#include<algorithm>
#define ll long long
#define N 1000005
ll x[N]={};
ll sum[N]={};
bool flag=false;
using namespace std;
int main(){
//关闭流同步
ios::sync_with_stdio(false);
ll n=0;
cin>>n;//等效scanf
for(ll i=1;i<=n;i++){
cin>>x[i];
if(x[i]&1)flag=true;
//x[i]&1是判定奇偶的快速方法,比较实用,可以加速60倍
}
if(flag)cout<<"Antinomy"<<endl;
//等效prinf("Antinomy");
else cout<<"XiJam"<<endl;
}
第三题: Interpretability
几何数学题。已知边长为1 2 4 8等比数列下去的边有f1 f2 f3条,求可以组成多少个三角形。
数学有一个三角形的初中结论:a+b>c任意成立。
而在本题中,变成了等腰三角形b>=a,(其中b为腰)
很多人会下意识考虑等边三角形作为第一种情况,其实大错特错。
实际上这题应该把所有等边三角形看成等腰三角形
举个例子1 1 1 6,
如果把6条权值为8的边考虑成等边就会丢掉三条边。
而如果考虑成等腰的话,那么值8的边可以组成三个等腰,和剩下的小边组成等腰三角形。
因此,这题应当优先考虑等腰的边,而不是等边。
#include<iostream>
#include<stack>
#include<string>
#include<cstring>
#include<algorithm>
#define ll long long
#define N 1000005
ll x[N]={};
ll sum[N]={};
bool flag=false;
using namespace std;
int main(){
ios::sync_with_stdio(false);
ll n=0,count1=0;
ll count2=0;
ll count3=0;
cin>>n;
for(ll i=1;i<=n;i++){
cin>>x[i];
//利用迭代循环实现不断判定等腰三角形存在的情况
while(x[i]>=2&&count2>=1){
count2--;
x[i]-=2;
count1++;
}
//剩下的就变成了底边,真的等边三角形
count2+=x[i]%3;
count1+=x[i]/3;
}
cout<<count1<<endl;
}
第四题 :Batch Normalization 1D
~~真实名字:拿头模拟题~~
很漂亮的模拟题,过程其实很清晰,而且题目又长又劝退,题面简单又单纯。可惜我没做对。
稍微讲一下题意:模拟这样一个过程:
1.给二维矩阵和一维矩阵的运算模式,利用运算规则进行精度计算
2.第一步,先求出两个定矩阵
3.第二步,进入训练状态循环n_b次,将进行两种运算
其一:求x_hat
其二:求moving_var和moving_mean,这个运算过程就是模拟过程。
4.结束:最后模拟运算一次,打印结果。
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include<cmath>
#include<list>
using namespace std;
long long n, c,n_b;
double eps, mo;
double x[205][205] = {};
double x_hat[500][500] = {};
double moving1[205] = {};
double moving2[205] = {};
double beta[20005] = {};
double gamma1[20005] = {};
double out[205][205] = {};
double t[205] = {};
list<string>s1;
double mxxx[50] = {};
double varx[50] = {};
//主代码从这里开始
int main() {
cin >> n >> c >> n_b >> eps >> mo;
for (int i = 0;i < n;i++) {
for (int j = 0;j < c;j++) {
cin >> x[i][j];//存x矩阵
}
}
for (int i = 0;i < c;i++) {
cin >> gamma1[i];//存gamma
}
for (int i = 0;i < c;i++) {
cin >> beta[i];//存beta
}
for (int i = 0;i < c;i++) {
cin >> moving1[i];//存moving—mean
}
for (int i = 0;i < c;i++) {
cin >> moving2[i];//存moving-var
}
for (int i = 0;i < c;i++) {
double tmp = 0;
for (int j = 0;j < n;j++) {
tmp += x[j][i];
}
mxxx[i] = tmp / n;//求mu的矩阵
}
for (int i = 0;i < c;i++) {
double tmp = 0;
for (int j = 0;j < n;j++) {
tmp += (x[j][i] - mxxx[i])* (x[j][i] - mxxx[i]);
}
varx[i] = tmp / n;//求var的矩阵
}
//开始训练
while (n_b--) {
for (int i = 0;i < n;i++) {
for (int j = 0;j < c;j++) {
t[1] = x[i][j] - mxxx[j];
t[2] = varx[j] + eps;
t[2] = sqrt(t[2]);
x_hat[i][j] = t[1] / t[2];//第一种训练的模拟过程
}
}//第二种训练的模拟过程*2
for (int j = 0;j < c;j++) {
t[1] = mo * moving1[j];
t[2] = (1.000000 - mo) * mxxx[j];
moving1[j] = t[1]+t[2];
}
for (int j = 0;j < c;j++) {
t[1] = mo * moving2[j];
t[2] = (1.00000 - mo) * varx[j];
moving2[j] = t[1]+t[2];
}
}
//训练结束,开始最后的运算
for (int i = 0;i < n;i++) {
for (int j = 0;j < c;j++) {
x_hat[i][j] = (x[i][j] - moving1[j]) / sqrt(moving2[j] + eps);
}
}//打印结果out
for (int i = 0;i < n;i++) {
for (int j = 0;j < c;j++) {
out[i][j] = gamma1[j] * x_hat[i][j] + beta[j];
printf("%.4f ", out[i][j]);
}
if (i != n - 1)cout << endl;
}
}
新生组第五题:小西和数字转换
思维
倒着思考第x个数以内,除y+1位是1,其余为0
如果不是,那么计数器+1,输出计数器的数字即可。
#include<iostream>
#include<string>
using namespace std;
int main ()
{
string num;
int n,x,y;
cin >> n >> x >> y;
cin >> num;
int ans = 0;
for ( int i = n - x ; i < n; i++ )
{
//两个判定限制条件,要么倒序y+1是1,其余都不能是1,不满足就扣钱
if ( ( num[i] == '1' && i != n - y - 1 ) || ( num[i] == '0' && i == n - y - 1 ) )
ans++;
}
cout << ans << endl;
return 0;
}
新生组第六题:小西和拼图
拼图,简单题
判定两个条件:
其一是m是否会被2整除
其二是是否存在任意拼图第二个数字和第三个数字相同
满足这两个即可。
(据说有一个数据n是读取失败了,有的人正确代码也错了,那么不改变n可能就给过了,可以去试试)
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
int n, m;
scanf("%d%d", &n, &m);
int a, b, c, d;
int k = 0;
while(n)
{
scanf("%d%d%d%d", &a, &b, &c, &d);
if (b == c)
{
k = 1;
}
n--;
}
if (k == 1 && m % 2 == 0)
printf("YES\n");
else printf("NO\n");
}
return 0;
}
新生组第七题:小西和复制粘贴
~~您就是cv工程师?!~~
这题是经典的倒叙思维题利用倒序由果导因
已知我们要第i个字母
我们从最后一步往前走走到起点不就知道我们需要第i个字符了么。
//您就是cv工程师??!
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include<list>
using namespace std;
long long n, k,m;
char s[2000005] = {};
long long x[200005] = {};
long long sum[200006] = {};
long long a[200005] = {};
long long b[200005] = {};
long long c[200005] = {};
list<string>s1;
//刚开始思考用链表然后发现爆了就没写下去
typedef struct node {
string s;
node *x;
}T,*tree ;
int main() {
cin >> k >> m;
cin >> s;
cin >> n;
//倒过来取步骤,方便正向进行,~i就是取反,判定是否i为0
//这么妖的代码一看就是抄lmgg的
for (long long i = n-1;~i;i--) {
cin >> a[i] >> b[i] >> c[i];
}
for (long long i = 0;i < k;i++) {
long long p = i;//你现在要找第i个数字是哪个字符
for (long long j = 0;j < n;j++) if(c[j]<=p){
long long tmp = b[j] - a[j];
if (c[j] + tmp > p)p = a[j] + p - c[j];
else p -= tmp;
}//那就倒退回去,如果比p大了,那么肯定不影响p的生活
//如果比p小了,要么取代了p,要么让p这个位置往前了。
//(建议自己手撸一下很快的)
cout << s[p];
}
}
新生组防ak: 小西和秀苑酱饼
这题是真的好题,就算放到正式组也是屈指可数的过题量
模拟+dfs,不愧是龙老板
感谢龙老板提供题解!
#include <bits/stdc++.h>
using namespace std;
#define N 510
#define INF 0x3f3f3f3f//最大值
int n, m, num, ans[N][N], vis[N][N];
char s[N][N];
void F(int x, int y, int z)//dfs(深度优先搜索)
{
if (x < 1 || x > n || y < 1 || y > m || vis[x][y] > 0)
return;//递归边界,如果出现了如上情况,那么直接终止
if (vis[x][y] == -1)//如果出现访问过并且未知可不可以走下去的情况,那么标记无穷大,然后终止访问
{
num = INF;
return;
}
//标记当前点已经经过但是不知道可不可以走
vis[x][y] = -1;
++num;
//如果这个点是n
if (s[x][y] == 'N')
{//z为进来的方向
if (z == 0 || z == 3)
{//那么就出去往这两个方向
F(x, y + 1, 0);
F(x - 1, y, 3);
}
else
{//那么就往这两个方向走,
F(x, y - 1, 2);
F(x + 1, y, 1);
}
}
else
{//那么进来就是z了
if (z == 0 || z == 1)
{//如果z从10进来,就从01出去
F(x, y + 1, 0);
F(x + 1, y, 1);
}
else
{//否则就从23出去
F(x, y - 1, 2);
F(x - 1, y, 3);
}
}
//确实可以走,那么就把访问点标记为可走
vis[x][y] = 1;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%s", s[i] + 1);
memset(ans, 0x3f, sizeof ans);
for (int i = 1; i <= n; ++i)
{
memset(vis, 0, sizeof vis);
num = 0;
for (int j = 1; j <= m; ++j)
{//从四个角落才可以出发,判定四个角落是否满足出发条件
if (s[i][j] == 'N')
F(i, j, 1);
else
F(i, j, 3);
//取当前最小值,因为多次访问会出现有大小的情况
ans[i][j] = min(ans[i][j], num);
}
}
for (int i = 1; i <= n; ++i)
{
memset(vis, 0, sizeof vis);
num = 0;
for (int j = m; j; --j)
{
if (s[i][j] == 'N')
F(i, j, 3);
else
F(i, j, 1);
ans[i][j] = min(ans[i][j], num);
}
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
printf(j == m ? "%d\n" : "%d ", ans[i][j] >= INF ? -1 : ans[i][j] * 2);
//结果乘2为最终答案
//你龙老板永远是你龙老板
return 0;
}