A. George and Sleep
输入连个时间 A,B,其中A表示起床时间,B表示睡了多长时间,求几点开始睡
05:50 05:44
00:06
#include<iostream>
#include<fstream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<ctype.h>
#include<algorithm>
#include<string>
#define PI acos(-1.0)
#define maxn 1000
#define INF 1<<25
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
using namespace std;
int main ()
{
int ch, cm, a, b;
char str[100];
gets(str);
sscanf(str, "%d:%d", &ch, &cm);
gets(str);
sscanf(str, "%d:%d", &a, &b);
b = cm - b;
if (b < 0) b += 60, ch--;
a = ch - a;
if (a < 0) a += 24;
printf("%02d:%02d\n",a, b);
return 0;
}
B George and Round
输入n,m。其中n为比赛需要的题目数,而m为题库的题目数,接下来输入n个数字,代表比赛题目的难度,另起一行再输入m个数字,代表题库中题目难度。George只能将题库中的题目难度降低,现在要问他从题库中选完题目之后,还需要自己再多出几道题目。
3 5 1 2 3 1 1 1 1 1
2
int main ()
{
int n, m, a[3100], i, j;
cin>>n>>m;
for (i = 0; i < n; i++)
cin>>a[i];
j = 0;
int t;
for (i = 0; i < m; i++)
{
cin>>t;
if (t >= a[j] && j < n) j++;
}
cout<<n - j<<endl;
return 0;
}
有一个数组 b ,每次可以进行如下操作:
取出两个数,且 bi ≥ bj.。然后两个数连起来,如concat(500, 10) = 50010,再将新的数字放入数组中。
如此循环,直到数组中只剩下一个数p。
现在输入一个数p (1 ≤ p < 10100000)。
问一开始数组当中最多能有几个数字。
9555
4
这道题目其实可以从p的末尾开始,找到第一个非零的数字,如:1230560,找到6,然后从这里将数字分为两半,如果前面半段的长度大于后半段,一定可以拆分,如果长度相同,比较两个数的首位,因为后半段的数字除了首位都是0。
char str[100010];
bool flag = true;
int main ()
{
gets(str);
int len = strlen(str);
int n = 0;
while(flag)
{
char a[100010], b[100010];
int j = len;
while(str[j-1] == '0' && j) j--;
j = j - 1;
if (j == 0) flag = false;
else
{
if (j > len - j)
{
len = j;
n++;
}
else if (j == len - j)
{
int k, ok = 1;
for (k = 0; k < j; k++)
if (str[k] < str[j + k])
{
ok = 0;
break;
}
if (ok)
{
n++;
len = j;
}
else flag = false;
}
else flag = false;
}
}
n++;
cout<<n<<endl;
return 0;
}
E. George and Cards
有一堆纸牌,共N张,数字分别为1到N,以任意顺序从左到右排在桌上。现在要从中保留K张纸牌,告诉你它们从左到右的排列书序(保证是之前的子集)。
现在以下的操作:
每次从已有的纸牌堆中选取一个连续子段(假设长度为w),然后将这个子段当中最小的一张牌取出。每次操作可以得到w分。
经过N-K次操作之后,问得到的分数最大为多少。
10 5 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10
30
这道题目可以确定,一定是按照从小到大的顺序取走不用的卡片。
在取 i 时,子段的左右两边都是比 i 小的且是要保留的数(因为比 i 小的不用保留的数已经取走了) (我们可以在纸牌的左右两端假想有两张不能取走的牌,数字为0)
所以可以开一个p数组记录位置。开一个set 来存放需要保留的卡片的位置,一开始将0 和 N+1 也加入到set中。
从1 到 n 进行遍历,如果是需要的卡片,则将位置加入到set当中,如果是不需要的卡片,就从set当中找出位于该卡片左右两端卡片的位置,两者之差的卡片数即为w。
再用一个树状数组来维护卡片数。
#include<iostream>
#include<fstream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<ctype.h>
#include<algorithm>
#include<string>
#define PI acos(-1.0)
#define maxn 1000100
#define INF 1<<25
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
using namespace std;
int n, k, p[maxn], b[maxn], s[maxn];
ll ans;
void add(int x, int t)
{
while(x <= n)
{
s[x] += t;
x += x & -x;
}
}
int sum(int x)
{
int d = 0;
while(x > 0)
{
d += s[x];
x -= x & -x;
}
return d;
}
set<int> F;
int main ()
{
cin>>n>>k;
F.insert(0), F.insert(n + 1);
for (int i = 1, x; i <= n; i++)
{
scanf("%d", &x);
p[x] = i;
add(i, 1);
}
for (int i = 1, x; i <= k; i++)
{
scanf("%d", &x);
b[x] = 1;
}
for (int i = 1; i <= n; i++) if (b[i]) F.insert(p[i]);
else
{
set<int>::iterator x, y;
x = F.lower_bound(p[i]);
y = x--;
ans += sum(*y - 1) - sum(*x);
add(p[i], -1);
}
cout<<ans<<endl;
return 0;
}