作为一只退役狗,有幸还能出3个题(E,F,H)
比赛描述
有次TC去某厂面试,被问了一道据面试官说小学生都会做的题,题面如下:
给n个16位无符号整数, 用二进制表示可组成一个很长的01串,要求将每个01串逆序(比如10的二进制为0000000000001001,逆序后为100100000000 0000),逆序后又得到n个16位无符号整数,求逆序后n个整数的最大值,以及其之前对应的数
输入
第一行为一个整数n (0 < n < 10^7)
第二行为n个16位无符号正整数
输出
逆序后n个整数的最大值及其之前所对应的数
样例输入
3
3 4 5
样例输出
49152 3
这个题本来想卡空间的,不让开数组,本质是考查位运算,没难度,某厂某面试官:"小学生都会"
#include
int main() {
int n, num, ans = 0, x, ma = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i ++) {
scanf("%d", &x);
num = 0;
for (int j = 0; j < 16; j ++) {
num <<= 1;
num |= (x & (1 << j)) ? 1 : 0;
}
if (ans < num) {
ans = num;
ma = x;
}
}
printf("%d %d\n", ans, ma);
}
比赛描述
给两个数列A,B,B数列的每个数可同时增加或减少,使其成为A数列的子数列(子数列是连续的一段),若不存在这样的子数列输出0,否则输出可能的子数列个数,并且对任意可行的子数列,找出A中删除B剩余值和的最大值。
输入
第一行两个数n,m ,分别表示数列A,B的大小(1 <= m,n <= 2000000)
第二行n个数 (1 <= a[i] <= 10^9)
第三行m个数 (1 <= b[i] <= 10^9)
输出
若不存在这样的子数列输出0,否则输出子数列个数及剩余和的最大值
样例输入
4 2
1 2 3 4
1 2
样例输出
3 7
提示
B数列保持不变,A-B={3,4},和为7
B数列同时增加1,A-B={1,4},和为5
B数列同时增加2,A-B={1,2},和为3
能变成的子数列个数为3,最大剩余和为7
这题目看数据肯定是一个O(n)的算法解决,由于B数列的增减是对其所有数字,假设B数列的某个数字B[i]增加了x,可以使其等于A数列的某个数字A[j],那么B[i + 1] + x是否等于A[i + 1]呢?可以明显看出来,决定因素在x上,也就是相邻两个数的差值,这样思路就出来了,处理出A数列和B数列相邻数字间的差值得到新的C数列和D数列,我们要做的就是找到C数列中有几个D数列,归根到底就是一个字符串匹配问题,用KMP算法轻松解决,剩余值可以通过预处理前缀和O(1)得到,注意当m等于1时需要特判。
#include
#include
#include
#define ll long long
using namespace std;
int const MAX = 2000005;
int a[MAX], b[MAX], nxt[MAX];
ll sum[MAX];
int n, m, cnt;
void get_next() {
nxt[0] = -1;
int i = 0, j = -1;
while (i < m) {
if (j == -1 || b[i] == b[j]) {
i ++;
j ++;
nxt[i] = j;
} else {
j = nxt[j];
}
}
}
ll KMP() {
n --;
m --;
get_next();
int i = 0, j = 0;
cnt = 0;
ll ans = 0;
while(i < n) {
if(j == -1 || a[i] == b[j]) {
i ++;
j ++;
} else
j = nxt[j];
if(j == m) {
ans = max(ans, sum[n] - sum[i] + sum[i - j - 1]);
cnt ++;
j = nxt[j];
}
}
return ans;
}
int main() {
scanf("%d %d", &n, &m);
int mi = 2000000000;
for (int i = 0; i < n; i ++) {
scanf("%d", &a[i]);
if (i == 0) {
sum[0] = a[i];
} else {
sum[i] = sum[i - 1] + a[i];
}
mi = min(a[i], mi);
}
for (int i = 0; i < m; i ++) {
scanf("%d", &b[i]);
}
if(m > n) {
printf("0\n");
} else {
if(m == 1) {
printf("%d %I64d\n", n, sum[n - 1] - mi);
} else {
for (int i = 0; i < n - 1; i ++) {
a[i] = a[i] - a[i + 1];
}
for (int i = 0; i < m - 1; i ++) {
b[i] = b[i] - b[i + 1];
}
ll ans = KMP();
if (ans == 0) {
printf("0\n");
} else {
printf("%d %I64d\n", cnt, ans);
}
}
}
}
比赛描述
传说中有个天空花园存在着一种极其珍贵的玫瑰,这种玫瑰不会凋谢,它有个杀马特的名字叫nodie玫瑰,nodie玫瑰一年只会开出十几朵, 情人节就要到了,TC准备去天空花园采这种花送给YSJJ,花园的管理员不会轻易就让人采到花,他将花园放到了一个平面直角坐标系中,花园的出入口相同,都处在坐标系的原点,管理员规定每人每次必须从花园的入口出发沿着规定的路径采花,路径只能是某种二次函数,可以在自己选择的路径上任意走动,但是在某一路径采完后必须回到入口,整个过程算一次采花,由于天空花园的花都非常珍贵,一个人最多采k次,TC用了些套路打探到nodie玫瑰只有n朵, 贪心的TC想采下所有的nodie玫瑰,请问TC能如愿以偿吗,如果不可以,输出poor TC,否则输出TC well done in x time(s),x代表采完所有nodie玫瑰所需要的最少采花次数。
输入
第一行一个数字T(1 <= T <= 15),表示数据组数
每组数据的第一行两个数字n和k,(0< k < n <=20)
接下来n行,每行2个数字代表一朵nodie玫瑰的坐标,坐标绝对值不超过1000
输出
若不能采光所有nodie玫瑰,输出poor TC;否则输出采完所有nodie玫瑰所需要的最少次数
样例输入
2
2 2
1.00 3.00
2.00 4.00
2 1
-1.00 1.00
-1.00 2.00
样例输出
TC well done in 1 time(s)
poor TC
提示
对第一组样例可通过路径y=-(x-2)^2+4
首先题目中的抛物线过原点,这样抛物线的方程就确定为y=ax^2+bx的形式,显然一条过原点的抛物线可被其他任意两个不重合的点(非原点)唯一确定,因此我们用两个点(x1,y1),(x2,y2)来表示每条抛物线,联立两个点的方程可得a=(x2y1-x1y2)/(x1x2(x1-x2)),通过a可得b=y1/x1-a*x1,用一个数组s[i][j]表示过点i和点j的抛物线的覆盖点的状态(1表示经过,0表示没经过),x1和x2不能相等且都不能为0,上面都处理完,就可以愉快的状压dp了,dp[sta]表示点覆盖状态为sta时的最小抛物线个数,因为其实有很多抛物线是多余的,故直接考虑当前状态下最先 (这里先后指的是点输入的顺序) 没有被覆盖的点如何被覆盖最优,转移方程就很容易写出来了。这样做的时间复杂度是O(n*2^n)
#include
#include
#include
#include
using namespace std;
int const INF = 0x6fffffff;
int const MAX = 21;
double const EPS = 1e-10;
double x[MAX], y[MAX], A[MAX][MAX];
int s[MAX][MAX], dp[1 << MAX];
int main() {
int T, n, k;
scanf("%d", &T);
while (T --) {
scanf("%d %d", &n, &k);
int all = (1 << n) - 1;
for (int i = 0; i < n; i ++) {
scanf("%lf %lf", &x[i], &y[i]);
}
for (int i = 0; i < n; i ++) {
for (int j = i + 1; j < n; j ++) {
if (fabs(x[i] - x[j]) < EPS || x[i] == 0 || x[j] == 0) {
s[i][j] = 0;
continue;
}
s[i][j] = (1 << i) | (1 << j);
double A = (x[j] * y[i] - x[i] * y[j]) / (x[i] * x[j] * (x[i] - x[j]));
if (fabs(A) < EPS) {
s[i][j] = 0;
continue;
}
double B = y[i] / x[i] - A * x[i];
for (int k = 0; k < n; k ++) {
if (k != i && k != j && fabs(A * x[k] * x[k] + B * x[k] - y[k]) < EPS) {
s[i][j] |= (1 << k);
}
}
}
}
for (int i = 0; i <= all; i ++) {
dp[i] = INF;
}
dp[0] = 0;
for (int sta = 0; sta <= all; sta ++) {
int i = 0;
while (sta & (1 << i)) {
i ++;
}
if (dp[sta] < INF) {
dp[sta | (1 << i)] = min(dp[sta | (1 << i)], dp[sta] + 1);
for (int j = i + 1; j < n; j ++) {
dp[sta | s[i][j]] = min(dp[sta | s[i][j]], dp[sta] + 1);
}
}
}
if (dp[all] <= k) {
printf("TC well done in %d time(s)\n", dp[all]);
} else {
printf("poor TC\n");
}
}
}