https://vjudge.net/contest/310810#overview
A
我们可以用 0…359 之间的角度来描述一个方向,现在给出两个方向 a , b,你需要求出,从 a 转到 b 最少需要的角度。
例如,从 70° 转到 180°,可以转 110°,也可以转 -250°
又比如,从315°转到45°,可以转90°,也可以转 -270°
定义一个角度 a 比另一个角度 b 小,当且仅当 a 的绝对值小于 b。
例如:180°比 -220°小,-45°比80°小。
特别的,如果两个角度的绝对值相同,我们规定正的角度比较小,比如180°小于-180°
Input
第一行两个 0 到 359之间的整数 a , b
Output
输出最少需要转的角度
Sample Input
315 45
Sample Output
90
我也不知道怎么解释,当心正负吧。
#include<bits/stdc++.h>
using namespace std;
int a,b,m,n;
int main(){
cin >> a>> b;
if(a>b) b += 360;
m = (b-a)%360;
n = -((360-b+a)%360);
if(abs(m)<abs(n)) cout <<m;
else if(abs(n)<abs(m)) cout << n;
else cout<<abs(m);
return 0;
}
B
小 Hi 有一个正整数 n,但他忘了这个数是啥了。他只记得 n 的所有约数的平均数是 a,n 的所有约数的调和平均数是 h ,且 a 和 h 都是正整数,现在小 Hi 想要你找出 n 的值。保证 n 存在,且小于等于 108
注:
n个数a1,a2…an的算术平均数为∑ai / n
n个数a1,a2…an的调和平均数为n / ∑(1/ai)
Input
第一行两个正整数 a , h
Output
输出一个正整数
Sample Input
3 2
Sample Output
6
猜测输出a*h就好了,嗯!猜测成功!
C
小 Hi 手上有 n 张面值互不相同的钱币,且面值都是 2 的幂次,现在他想知道,他可以组合出多少种小于等于 c 的正整数金额。
Input
第一行两个正整数 n , c (1 ≤ n ≤ 50, 1 ≤ c ≤ 1018)
第二行n个互不相同的正整数,表示小Hi手上钱币的面值,保证面值都是 2 的幂次,且不超过 1018
Output
输出一个整数表示答案
Sample Input
3 10
4 1 8
Sample Output
5
Hint
可以拼出 1, 4, 5, 8, 9
先全部转化成二进制,然后dp;
d
p
[
i
]
dp[i]
dp[i] 表示在最高位为 i 的时候,不大于 c 的金额的种类。
先预处理出来一个 sum 数组,表示在最高位为 i 的时候,用现有的钱可以组合出多少种金额。
于是,若 c 的二进制从低位开始的第 i 位为1,若此时有这种金额的货币,那么
d
p
[
i
]
=
d
p
[
i
−
1
]
+
s
u
m
[
i
−
1
]
dp[i] = dp[i-1] + sum[i-1]
dp[i]=dp[i−1]+sum[i−1],如果没有这种金额的货币,
d
p
[
i
]
=
s
u
m
[
i
−
1
]
dp[i] = sum[i-1]
dp[i]=sum[i−1];若为0,
d
p
[
i
]
=
d
p
[
i
−
1
]
dp[i] = dp[i-1]
dp[i]=dp[i−1]。
#include<bits/stdc++.h>
using namespace std;
set<long long int> st;
bool is[80];
bool big[80];
typedef long long int ll;
long long int f[80],sum[80];
long long int n,c,a,M=1;
int main(){
cin >> n>> c;
memset(is,false,sizeof is);
memset(f,0,sizeof f);
for(int i = 0;i < n;i ++){
cin >> a;
st.insert(a);
}
for(int i = 0;i<=70;i++){
if(st.count(M)==1) is[i] = true;
M <<= 1ll;
}
int fi = 0;
while(c){
if(c&1) big[fi]=true;
else big[fi]=false;
fi++;
c>>=1ll;
}
fi--;
if(is[0]) sum[0] = 2ll;
else sum[0] = 1ll;
for(int i = 1;i <= 70;i ++){
if(is[i]) sum[i] = sum[i-1]*2ll;
else sum[i] = sum[i-1];
}
if(is[0]&&big[0]) f[0] = 2ll;
else f[0] = 1ll;
for(int i=1;i<=70;i++){
if(big[i]&&is[i]) f[i]=f[i-1]+sum[i-1];
else if(big[i]) f[i]=sum[i-1];
else f[i]=f[i-1];
}
cout << f[70]-1ll;
return 0;
}
D
你有 n 个数位( 1 到 9 ),现在你需要用他们组成 k 个正整数,使得最大的数最小
Input
第一行两个正整数 n , k (1 ≤ k ≤ n ≤ 105)
第二行一个长度为 n 的数字串,表示你拥有的数位。
Output
出最大的数的最小值
Sample Input
7 4
4412377
Sample Output
34
Hint
组成:17, 34, 27, 4
// copy from zzy
#include <bits/stdc++.h>
using namespace std;
int n,k;
string s;
int num[10];
int main(){
cin>>n>>k;
cin>>s;
for (int i=0;i<n;i++)
num[(int)s[i]-(int)'0']++;
int l = n/k+1, m = n%k;//l是长串的长度,m是长串的个数
if (n%k == 0) { //所有串长度一样
m += k; l --;
}
for (int i = 1; i <= l; i ++){
int j=0;
while (j<=9){
if (num[j]>=m){ //每个长串都填一个
cout<<j;
num[j]-=m;
break;
} else { //有些串已经不再可能是最大的串了
m-=num[j];
num[j]=0;
}
j++;
}
}
return 0;
}