A. I Count Two Three
题意:找出最小的不小于n的可分解为2^a3^b5^c7^d的形式的数
思路:考虑到n的范围不大,且2/3/5/7的指数也不大,可以直接预处理出答案,然后二分查找
#include<cstdio>
#include<algorithm>
using namespace std;
const long long N = 1e9 + 10;
vector<long long> v;
long long quickpow(long long x, int n) {
long long res = 1;
while(n) {
if(n & 1)
res = res * x;
x = x * x;
n /= 2;
}
return res;
}
void solve() {
long long x, y, z, u;
for(int i = 0; i <= 30; i += 1) {
x = quickpow(2, i);
for(int j = 0; j <= 19; j += 1) {
y = quickpow(3, j);
if(x * y > N)
continue;
for(int k = 0; k <= 13; k += 1) {
z = quickpow(5, k);
if(x * y * z > N)
continue;
for(int p = 0; p <= 11; p += 1) {
u = quickpow(7, p);
if(x * y * z * u > N)
continue;
v.push_back(x * y * z * u);
}
}
}
}
sort(v.begin(), v.end());
}
int main() {
solve();
int T;
scanf("%d", &T);
while(T--) {
int n;
scanf("%d", &n);
printf("%lld\n", *(lower_bound(v.begin(), v.end(), (long long)n)));
}
return 0;
}
B. Cure
题意:给你一个整数n,让你输出i∈[1...n]的1/i^2的和
思路:当n较大时,1/i^2的结果已经接近于零,找出这个i,之后的n>i答案都相同,所有也是预处理答案
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e6;
double res[N];
char str[2000];
int main() {
for(long long i = 1; i <= N; i += 1)
res[i] = res[i - 1] + 1.0 / (i * i);
while(~scanf("%s", str)) {
int l = strlen(str);
if(l > 7)
printf("%.5f\n", res[N]);
else {
int x = 0;
for(int i = 0; i < l; i += 1)
x = x * 10 + str[i] - '0';
if(x > N)
x = N;
printf("%.5f\n", res[x]);
}
}
return 0;
}
D. Tea
思维
题意:初始有一个茶壶,不知道里面具体有多少茶水,但给你一个茶水体积的范围[l,r],现让你往两个茶杯里倒水,倒到最后两个茶杯里的水体积相差不超过1,茶壶里的水剩余量也不超过1,问最少需要操作的次数
思路:首先分四种情况考虑,
1.r<=1 ,茶壶里的水最多为1,可以不用倒 ans = 0
2.r<=2 ,往任意一个茶杯里倒1的水便结束 ans = 1
3.l==r || r-l==1 , 倒两次l/2结束, ans = 2
4.r-l>1 前两次分别倒l/2 l/2+1 之后轮着倒2,始终保持两茶杯里水1的体积差,因为茶壶最后可以保留一体积的水,所以答案是 2+(r-l-1)/2 = (r - l) /2 + 1
#include<cstdio>
using namespace std;
int main() {
long long l, r;
while(~scanf("%lld%lld", &l, &r)) {
if(r <= 1)
printf("0\n");
else if(r <= 2)
printf("1\n");
else if(l == r || r - l == 1)
printf("2\n");
else {
if(l == 0)
l = 1;
printf("%lld\n", (r - l) / 2 + 1);
}
}
return 0;
}
E. Balanced Game
题意:石头剪刀布存在一种平衡局面,即每个人克除他以外一半的人,还被除他以外一半的人克,问给你人数,是否能构成这样一种局面
思路:n为奇数时成立
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5 + 5;
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n;
scanf("%d", &n);
if(n % 2)
printf("Balanced\n");
else
printf("Bad\n");
}
return 0;
}
F. The Best Path
图论 欧拉回路/欧拉路径
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5 + 5;
int arr[N], d[N], ver, link;
int solve() {
int type = 0;
int res = 0;
for(int i = 1; i <= ver; ++i) {
if(d[i] & 1)
type += 1;
}
if(type != 0 && type != 2)
return -1;
for(int i = 1; i <= ver; ++i) {
d[i]=(d[i]+1)/2;
if(d[i] & 1)
res ^= arr[i];
}
if(!type) {
for(int i = 1; i <= ver; ++i)
res = max(res, res ^ arr[i]);
}
return res;
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &ver, & link);
for(int i = 1; i <= ver; ++i) {
scanf("%d", &arr[i]);
d[i] = 0;
}
int u, v;
for(int i = 0; i < link; ++i) {
scanf("%d%d", &u, &v);
d[u] += 1;
d[v] += 1;
}
int res = solve();
if(res == -1)
printf("Impossible\n");
else
printf("%d\n", res);
}
return 0;
}
G. Sort
题意:一个长度为n的序列,每次你可以选择序列中的<=k个数合并,合并一次的代价是所选择的数的和,题目要求将所有数合并为1个,且代价不超过T,问最小的k是多少?
思路:
二分+优先队列
先将序列从小到大排序。若每次能合k个,其实是最优的情况(因为每个数实际上被重复算的次数是最少的),但k值的选择并不能保证每次合并都是k个数合并,所以前期做一个处理,先将前(1+(n-1)%(k-1))个数合并成一个数再放回原序列,那么之后每次合并从序列中就都能选前k小的数合并,直到所有数被合并为一个,总代价最小
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int N = 1e5 + 5;
int pre[N], arr[N], n, k;
priority_queue<int, vector<int>, greater<int> >que;
bool solve(int M) {
while(!que.empty())
que.pop();
long long res = 0;
int x = (n - 1) % (M - 1);
if(x) {
x += 1;
res += pre[x];
que.push(res);
}
for(int i = x + 1; i <= n; ++i)
que.push(arr[i]);
while(que.size() > 1) {
long long x = 0;
int p = min((int)que.size(), M);
while(p--) {
x += que.top();
que.pop();
}
res += x;
if(res > k)
return 0;
que.push(x);
}
return res <= k;
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; ++i)
scanf("%d", &arr[i]);
sort(arr + 1, arr + 1 + n);
for(int i = 1; i <= n; ++i)
pre[i] = pre[i - 1] + arr[i];
int L = 2;
int R = n;
int res = n;
while(L <= R) {
int M = (L + R) / 2;
if(solve(M)) {
res = min(res, M);
R = M - 1;
} else
L = M + 1;
}
printf("%d\n", res);
}
return 0;
}
J. Herbs Gathering
由于 cost 和 socre 范围高达1e9所以不能用dp,改用搜索
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5 + 5;
struct data {
long long cost, score;
bool operator <(const data u) const {
return score * u.cost > u.score * cost;
}
} p[N];
int n;
long long limit, res;
void solve(int pos, long long w, long long c) {
if(w > res)
res = w;
if(pos >= n || c > limit || (double)w + 1.0 * p[pos].score / p[pos].cost * (limit - c) <= (double)res )
return ;
if(c + p[pos].cost <= limit)
solve(pos + 1, w + p[pos].score, c + p[pos].cost);
solve(pos + 1, w, c);
}
int main() {
while(~scanf("%d%lld", &n, &limit)) {
for(int i = 0; i < n; ++i)
scanf("%lld%lld", &p[i].cost, &p[i].score);
sort(p, p + n);
res = 0;
solve(0, 0, 0);
printf("%lld\n", res);
}
return 0;
}