upc训练赛第十二场
文章目录
前言
今天的题不会的是真不会,像后两个英文题还有C题和H题,劝退啊。
A 马拦过河卒(暴力+动态规划)
棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。棋盘用坐标表示,A点(0, 0)、B点(n, m)(n, m为不超过20的整数),同样马的位置坐标是需要给出的。现在要求你计算出卒从A点能够到达B点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
输入
6 6 3 3
输出
3
其实就是跟走棋盘一样 关系方程是f[i][j]=f[i-1][j]+f[i][j-1],所以dfs也行
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[101][101];
long long int f[101][101]; //记得开long long
int dx[8]= {1,2,2,1,-1,-2,-2,-1}; //偷懒
int dy[8]= {2,1,-1,-2,-2,-1,1,2};
int n,m,x,y;
cin >> n >> m >> x >> y;
memset(a,0,sizeof(a)); //初始化
memset(f,0,sizeof(f)); //初始化
for(int i=0; i<=7; i++)
{
if(x+dx[i]>=0&&x+dx[i]<=n&&y+dy[i]>=0&&y+dy[i]<=m)
a[x+dx[i]][y+dy[i]]=1; //不能走的马控制得八个点标记上
}
a[x][y]=1; // 马那个点也不行
f[0][0]=1;
for(int i=0; i<=n; i++)
{
for(int j=0; j<=m; j++)
{
if(i-1>=0&&a[i-1][j]==0)
f[i][j]+=f[i-1][j];
if(j-1>=0&&a[i][j-1]==0)
f[i][j]+=f[i][j-1];
}
}
cout<<f[n][m]<<endl;
return 0;
}
B 选数(dfs)
已知 n 个整数 x1,x2,…,xn,以及一个整数 k(k<n)。从 n 个整数中任选 k 个整数相加,可分别得到一系列的和。例如当 n=4,k=3,4 个整数分别为 3,7,12,19 时,可得全部的组合与它们的和为:
3+7+12=22
3+7+19=29
7+12+19=38
3+12+19=34。
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数:3+7+19=29)。**
输入
4 3
3 7 12 19
输出
1
写得有点麻烦了,dfs经典题,好像是noip普及组2002
#include <bits/stdc++.h>
using namespace std;
int n,k;
long long a[25],ans;
bool vis[25];
bool fun(long long n) //判断质数
{
if(n==1||n==0)
{
return false;
}
else
{
for(int i=2; i*i<=n; i++)
{
if(n %i==0)
{
return false;
}
}
return true;
}
}
void dfs(int s,int t,long long sum) // s是位置,t是计数的,sum累加数
{
if(t==k)
{
if(fun(sum))
{
ans++;
}
return;
}
for(int i=s+1; i<=n; i++)
{
if(!vis[i])
{
vis[i] = true; //貌似没必要???
dfs(i,t+1,sum+a[i]);
vis[i] = false;
}
}
}
int main()
{
cin >> n >> k;
for(int i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
}
dfs(0,0,0);
cout << ans << endl;
return 0;
}
C.产生数(dfs)
给出一个整数 n(n<1030) 和 k 个变换规则(k<=15)。
规则:
一位数可变换成另一个一位数:
规则的右部不能为零。
例如:n=234。有规则(k=2):
2-> 5
3-> 6
上面的整数 234 经过变换后可能产生出的整数为(包括原数):
234
534
264
564
共 4 种不同的产生数
问题:
给出一个整数 n 和 k 个规则。
求出:
经过任意次的变换(0次或多次),能产生出多少个不同整数。
仅要求输出个数。
这个没弄出来,感觉应该是搜素,待补
D 级数求和 (循环,枚举)
已知:Sn= 1+1/2+1/3+…+1/n。显然对于任意一个整数K,当n足够大的时候,Sn大于K。
现给出一个整数K(1<=k<=15),要求计算出一个最小的n;使得Sn>K。
水题,记得用double
E 幸运数字 (枚举)
出现好几次了。。。
F 对撞(模拟,函数)
小明发明了一个数字对撞机,两个位数相同的整数可以进行碰撞。碰撞过程中,将两个 整数的每一位进行比较,较小的那个数字会被撞得粉碎,较大的数字保留下来(如果两数 相同,都会保留)。例如下面例子中:两个整数 13570 和 21673 碰撞后,对应数位上较小的值已经消失,碰撞的结果为:第一 个数字剩下 37,第二个数字剩下 2673。
现在小明想让你写一个程序来显示数字碰撞机的结果,输入两个整数,输出碰撞后的两 个数字。(注意最终结果不能包含多余的前导 0)
输入
样例1
13570
21673
样例2
300
500
样例3
1234
5678
输出
37
2673
0
500
BOOM
5678
铁定有人觉得样例把情况给全了,其实这题巨坑,补两组数据吧
输入
0030
0400
输出
3
40
思路:就是把情况考虑全,开两个数组存两组数,按题意模拟后,扫一遍看一下是不是没有数了,再看一下是不是应该输出的是0,其他情况输出即可。
#include<bits/stdc++.h>
using namespace std;
string s1,s2;
int a[1005],b[1005];
int n1,n2;
int fun(int a[])
{
for(int i=0;i<n1;i++)
{
if(a[i] != -1)
return 0;
}
return 1;
}
int jk(int a[])
{
for(int i=0;i<n1;i++)
{
if(a[i] != 0 && a[i] != -1) //不是0就是-1 那就是0;
return 0;
}
return 1;
}
int main()
{
int flag=0;
cin >> s1 >> s2; //别问我为啥吗,无奈之举,
n1 = s1.length();
n2 = s2.length();
for(int i=0;i<n1;i++)
{
a[i] = s1[i]-'0'; //记得转换下
}
for(int i=0;i<n2;i++)
{
b[i] = s2[i]-'0';
}
for(int i=0;i<n1;i++)
{
if(a[i]>b[i]) //废掉的标记一下
{
b[i]=-1;
}
else if(a[i]<b[i])
{
a[i]=-1;
}
}
if(fun(a)==1) //特判1
{
cout << "BOOM" << endl;
}
else if(jk(a)==1) //特判2
{
cout << 0 << endl;
}
else
{
for(int i=0;i<n1;i++)
{
if(a[i] != -1)
{
if(a[i] != 0) //别输出一个前导0;
{
flag = 1;
cout << a[i];
}
else if(a[i] == 0 && flag == 1)
{
cout << a[i];
}
}
}
cout << endl;
}
flag=0; //下面的就是改个数组名了。
if(fun(b)==1)
{
cout << "BOOM" << endl;
}
else if(jk(b)==1)
{
cout << 0 << endl;
}
else
{
for(int i=0;i<n1;i++)
{
if(b[i] != -1)
{
if(b[i] != 0)
{
flag = 1;
cout << b[i];
}
else if(b[i] == 0 && flag == 1)
{
cout << b[i];
}
}
}
cout << endl;
}
return 0;
}
G 差值求和(规律)
**小明最近学习了差的绝对值,|a-b|表示a-b的绝对值,若a-b>=0,则|a-b|=a-b;若a-b<0,则|a-b|=-(a-b)。
经过几次练习,小明已经熟练掌握了差的绝对值,现在他找来了N个整数,开始任意取出两个数,求差的绝对值,再将所有差的绝对值相加。例如N=4,有4个整数,分别是1,2,3,4。任取两个数有6种取法,|1-2|=1,|1-3|=2,|1-4|=3,|2-3|=1,|2-4|=2,|3-4|=1,它们的和就是10。
由于运算量太大,累坏了小明。请你写一个程序帮他计算一下吧。
输入
第一行一个整数n,表示有n个整数
第二行n个整数,表示小明写下的n个整数
输出
输出一个数,表示任意两数差的绝对值之和。
样例输入 Copy
【样例1】
3
3 1 2
【样例2】
4
1 2 3 4
样例输出 Copy
【样例1】
4
【样例2】
10
提示
样例1解释:|3-1|=2,|3-2|=1,|1-2|=1,答案为4
对于40%的数据,n<=1000,0<=每个数<=1000
对于70%的数据,输入数据保证第二行的n个数字从小到大有序。
对于100%的数据,n<=100000,0<=每个数<=1,000,000,000**
这看一眼数据就知道暴力是不可能的,先升序排序,找规律,首先肯定是一个循环搞定的,我们要算两个数的绝对值之和,那就是挑两个数大减小,排序后最大的数在最后一位,他要减前面n-1个数数就是(n-1)a[n],当然这是一个极限情况,对于任意的a[i],要减i-1个数,被减n-i次,所以就是(2*i-n-1)a[i]
#include<bits/stdc++.h>
using namespace std;
long long int a[1000002];
int main()
{
long long int n,sum=0;
cin >> n;
for(int i=1;i<=n;i++)
{
cin >> a[i];
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
{
sum+=a[i]*(2*i-1-n);
}
cout << sum << endl;
return 0;
}
H 取数游戏(这个不会)
J Unhappy Hacking I (模拟)
Sig has built his own keyboard. Designed for ultimate simplicity, this keyboard only has 3 keys on it: the 0 key, the 1 key and the backspace key.
To begin with, he is using a plain text editor with this keyboard. This editor always displays one string (possibly empty). Just after the editor is launched, this string is empty. When each key on the keyboard is pressed, the following changes occur to the string:
The 0 key: a letter 0 will be inserted to the right of the string.
The 1 key: a letter 1 will be inserted to the right of the string.
The backspace key: if the string is empty, nothing happens. Otherwise, the rightmost letter of the string is deleted.
Sig has launched the editor, and pressed these keys several times. You are given a string s, which is a record of his keystrokes in order. In this string, the letter 0 stands for the 0 key, the letter 1 stands for the 1 key and the letter B stands for the backspace key. What string is displayed in the editor now?
Constraints
1≤|s|≤10 (|s| denotes the length of s)
s consists of the letters 0, 1 and B.
The correct answer is not an empty string.
输入
01B0
输出
00
按照题意模拟即可
#include<stdio.h>
#include <bits/stdc++.h>
using namespace std;
int main()
{
char a[109];
char b[109];
int sum=0;
cin >> a;
for(int i=0;i<strlen(a);i++)
{
if(a[i]=='0'||a[i]=='1')
{
b[sum]=a[i]-'0';
sum++;
}
else if(a[i]=='B')
{
if(sum==0)
{
continue;
}
else
{
sum--;
}
}
}
for(int i=0;i<sum;i++)
{
printf("%d",b[i]);
}
}
K Be Together(循环)
Evi has N integers a1,a2,…,aN. His objective is to have N equal integers by transforming some of them.
He may transform each integer at most once. Transforming an integer x into another integer y costs him (x−y)2 dollars. Even if ai=aj(i≠j), he has to pay the cost separately for transforming each of them.
Find the minimum total cost to achieve his objective.
Constraints
1≤N≤100
−100≤ai≤100
输入
2
4 8
输出
8
其实找到一个数使数组中每个数跟它差的和最小,那就找平均数呗。但是找平均数到底向哪里去整是个问题,所以都试一下再比较
#include<bits/stdc++.h>
using namespace std;
long long int a[1009],sum1=0,sum=0,n,sum2=0,k,t;
int main()
{
cin >> n;
for(int i=0;i<n;i++)
{
cin >> a[i];
sum+=a[i];
}
t=sum/n;
for(int i=0;i<n;i++)
{
k=a[i]-t;
sum1+=k*k;
}
t++;
for(int i=0;i<n;i++)
{
k=a[i]-t;
sum2+=k*k;
}
sum1=min(sum1,sum2);
cout << sum1 << endl;;
return 0;
}
总结
第一次写博客,嘿嘿。