搭积木
小明有一袋子长方形的积木,如果一个积木A的长和宽都不大于另外一个积木B的长和宽,则积木A可以搭在积木B的上面。好奇的小明特别想知道这一袋子积木最多可以搭多少层,你能帮他想想办法吗?定义每一个长方形的长L和宽W都为正整数,并且1 <= W <= L <= INT_MAX, 袋子里面长方形的个数为N, 并且 1 <= N <= 1000000.假如袋子里共有5个积木分别为 (2, 2), (2, 4), (3, 3), (2, 5), (4, 5), 则不难判断这些积木最多可以搭成4层, 因为(2, 2) < (2, 4) < (2, 5) < (4, 5)。
#include
#include
using namespace std;
#define max_n 1000000
struct Data {
int x, y;
} arr[max_n + 5];
int val[max_n + 5];
int len[max_n + 5], ans;
bool cmp(const Data &a, const Data &b) {
if (a.x - b.x) return a.x < b.x;
return a.y < b.y;
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> arr[i].x >> arr[i].y;
}
sort(arr, arr + n, cmp);
for (int i = 0; i < n; i++) {
val[i] = arr[i].y;
}
len[0] = -1;
ans = 0;
for (int i = 0; i < n; i++) {
int pos = upper_bound(len, len + ans + 1, val[i]) - len;
ans = max(ans, pos);
len[pos] = val[i];
}
cout << ans << endl;
return 0;
}
魔法深渊
题目描述
前几个月放映的头号玩家简直火得不能再火了,作为一个探索终极AI的研究人员,月神自然去看了此神剧。由于太过兴奋,晚上月神做了一个奇怪的梦,月神梦见自己掉入了一个被施放了魔法的深渊,月神想要爬上此深渊。已知深渊有N层台阶构成(1 <= N <= 1000),并且每次月神仅可往上爬2的整数次幂个台阶(1、2、4、....),请你编程告诉月神,月神有多少种方法爬出深渊.
#include
using namespace std;
#define max_n 1000
#define mod_num (1000000000LL + 3)
long long f[max_n + 5];
void init() {
f[0] = 1;
for (int i = 1; i <= max_n; i++) {
for (int j = 1; j <= i; j <<= 1) {
f[i] += f[i - j];
f[i] %= mod_num;
}
}
return ;
}
int main() {
init();
int m, n;
cin >> m;
while (m--) {
cin >> n;
cout << f[n] << endl;
}
return 0;
}
善变的同伴
题目描述
又到了吃午饭的时间,你和你的同伴刚刚研发出了最新的GSS-483型自动打饭机器人,现在你们正在对机器人进行功能测试。
为了简化问题,我们假设午饭一共有N个菜,对于第i个菜,你和你的同伴对其定义了一个好吃程度(或难吃程度,如果是负数的话……)A[i],
由于一些技(经)术(费)限制,机器人一次只能接受一个指令:两个数L, R——表示机器人将会去打第L~R一共R-L+1个菜。
本着不浪费的原则,你们决定机器人打上来的菜,含着泪也要都吃完,于是你们希望机器人打的菜的好吃程度之和最大
然而,你善变的同伴希望对机器人进行多次测试(实际上可能是为了多吃到好吃的菜),他想知道机器人打M次菜能达到的最大的好吃程度之和
当然,打过一次的菜是不能再打的,而且你也可以对机器人输入-1, -1,表示一个菜也不打
#include
using namespace std;
#define max_n 100000
struct Node {
int val, flag;
int l, r;
} l[max_n + 5];
int n, m, head;
void del(int p) {
if (p == 0) return ;
l[p].flag = 1;
l[l[p].l].r = l[p].r;
l[l[p].r].l = l[p].l;
l[p].l = l[p].r = 0;
return ;
}
typedef pair PII;
inline int sign(int x) {
if (x < 0) return -1;
if (x > 0) return 1;
return 0;
}
int main() {
cin >> n >> m;
l[0].r = 1, l[0].l = 0;
for (int i = 1; i <= n; i++) {
cin >> l[i].val;
l[i].l = i - 1;
l[i].r = (i + 1) * (i < n);
}
set s;
int p = l[0].r, cnt = 0, sum = 0;
while (p) {
while (l[p].r && sign(l[p].val) * sign(l[l[p].r].val) >= 0) {
l[p].val += l[l[p].r].val;
del(l[p].r);
}
s.insert(PII(abs(l[p].val), p));
if (l[p].val > 0) cnt += 1, sum += l[p].val;
p = l[p].r;
}
while (cnt > m) {
int ind = s.begin()->second;
s.erase(s.begin());
if (l[ind].flag) continue;
if ((l[ind].r && l[ind].l) || l[ind].val > 0) {
sum -= abs(l[ind].val);
cnt -= 1;
l[ind].val += l[l[ind].l].val;
l[ind].val += l[l[ind].r].val;
del(l[ind].l); del(l[ind].r);
s.insert(PII(abs(l[ind].val), ind));
} else {
del(ind);
}
}
cout << sum << endl;
return 0;
}
合并数组
题目描述
请实现一个函数,功能为合并两个升序数组为一个升序数组
using namespace std;
int arr[3][100000];
int read_line_to(int k, int &n) {
int a;
n = 0;
while (~scanf("%d", &a)) {
arr[k][n++] = a;
if (getchar() == '\n') break;
}
return n;
}
int solve() {
int n, m;
if (!read_line_to(0, n)) return 0;
read_line_to(1, m);
int p1 = 0, p2 = 0, t = 0;
while (p1 < n || p2 < m) {
if (p2 == m || (p1 < n && arr[0][p1] < arr[1][p2])) {
arr[2][t++] = arr[0][p1++];
} else {
arr[2][t++] = arr[1][p2++];
}
}
for (int i = 0; i < t; i++){
i && cout << ",";
cout << arr[2][i];
}
cout << endl;
return t;
}
int main() {
int a, k = 0;
while (solve()) ;
return 0;
}
游戏海报
小明有26种游戏海报,用小写字母"a"到"z"表示。小明会把游戏海报装订成册(可能有重复的海报),册子可以用一个字符串来表示,每个字符就表示对应的海报,例如abcdea。小明现在想做一些“特别版”,然后卖掉。特别版就是会从所有海报(26种)中随机选一张,加入到册子的任意一个位置。
那现在小明手里已经有一种海报册子,再插入一张新的海报后,他一共可以组成多少不同的海报册子呢?
#include
using namespace std;
char str[25];
int p[25], n, ans = 0;
int count_one(int x) {
int cnt = 0;
while (x) {
cnt += 1;
x &= (x - 1);
}
return cnt;
}
int main() {
str[0] = 1;
cin >> str;
n = strlen(str);
for (int i = 0; i <= n; i++) p[i] = (1 << 26) - 1;
for (int i = 0; str[i]; i++) {
ans += count_one(p[i]);
if ((p[i] & (1 << (str[i] - 'a'))) == 0) continue;
int mask = ((1 << 26) - 1) ^ (1 << (str[i] - 'a'));
for (int j = i; str[j] == str[i]; j++) {
p[j + 1] &= mask;
}
}
ans += count_one(p[n]);
cout << ans << endl;
return 0;
}
latex爱好者
latex自然是广大研究人员最喜欢使用的科研论文排版工具之一。月神想在iPhone 上查阅写好的paper,但是无赖iPhone 上没有月神喜欢使用的阅读软件,于是月神也希望像tex老爷爷Donald Knuth那样自己动手do it yourself一个。在DIY这个阅读软件的过程中,月神碰到一个问题,已知iPhone屏幕的高为H,宽为W,若字体大小为S(假设为方形),则一行可放W / S(取整数部分)个文字,一屏最多可放H / S (取整数部分)行文字。已知一篇paper有N个段落,每个段落的文字数目由a1, a2, a3,...., an表示,月神希望排版的页数不多于P页(一屏显示一页),那么月神最多可使用多大的字体呢?
#include
using namespace std;
const int max_n = 100000;
int val[max_n + 5];
int n, p, h, w;
bool check(int mid) {
int cnt = w / mid, sum = 0;
for (int i = 0; i < n; i++) {
sum += val[i] / cnt + (val[i] % cnt != 0);
}
return sum <= (h / mid) * p;
}
int bs(int l, int r) {
if (l == r) return l;
int mid = (l + r + 1) >> 1;
if (check(mid)) return bs(mid, r);
return bs(l, mid - 1);
}
int main() {
while (cin >> n >> p >> h >> w) {
for (int i = 0; i < n; i++) cin >> val[i];
cout << bs(1, w) << " ";
}
return 0;
}
回文字符串
最大回文子串是被研究得比较多的一个经典问题。最近月神想到了一个变种,对于一个字符串,如果不要求子串连续,那么一个字符串的最大回文子串的最大长度是多少呢。
#include
#include
#include
using namespace std;
string str1, str2;
int f[1005][1005] = {0};
int main() {
cin >> str1;
str2 = str1;
reverse(str1.begin(), str1.end());
for (int i = 1; i <= str1.size(); i++) {
for (int j = 1; j <= str2.size(); j++) {
f[i][j] = max(f[i - 1][j], f[i][j - 1]);
if (str1[i - 1] == str2[j - 1]) {
f[i][j] = max(f[i][j], f[i - 1][j - 1] + 1);
}
}
}
cout << f[str1.size()][str1.size()] << endl;
return 0;
}