【A】水题,就是要注意特判,真是被自己聪明了一把,以为12点计时的时候12:00不合法,其实是合法的,被连续hack2次,整场崩溃。
【复杂度】O(1)
【代码君】
char s[10];
int main()
{
int n;
cin>>n;
cin>>s;
int x = (s[0]-'0')*10+(s[1]-'0');
int y = (s[3]-'0')*10+(s[4]-'0');
if(n==12){
if(x>12){
if(s[1] == '0') s[0] = '1';
else s[0] = '0';
}
if(x == 0) s[0] = '1';
if(y>59) s[3]='1';
cout<<s<<endl;
}
else{
int ans = 0;
if(x==0 && y==0){
cout<<s<<endl;
return 0;
}
if(x>23){
if(s[1] == '0') s[0] = '1';
else s[0] = '0';
}
if(y>59) s[3] ='1';
cout<<s<<endl;
}
}
【B】水题,判断元音字母的个数是否等于每一个a[i]即可。
【复杂度】O(n)
【C】两种解法
【解法1】set在线乱搞,定义两个集合set<int> s1, multise<int> s2, s1存的是破化的元素的下标,s2存的是区间的和。sum[]数组存的是元素前缀和.每次破化一个元素x时,在s1中找到大于x最小的已被破化的元素下标p2, 和小于x最大的已被破化的下标p1, 那么x > p1 && x < p2 所以(p1, p2)区间被分成连个区间,把这两个区间的值存到s2中,删除(p1, p2)整个区间的值,输出s2中最大值。
【复杂度】O(nlogn)
【代码君】
const int maxn = 1e6+10;
set<int>s1;
multiset<long long>s2;
long long sum[maxn];
int main()
{
int n,x;
scanf("%d",&n);
for(int i = 1; i <= n; i++) scanf("%lld",&sum[i]),sum[i] += sum[i-1];
for(int i = 1; i <= n; i++){
scanf("%d",&x);
if(i == 1){
s1.insert(x);
s2.insert(sum[n]-sum[x]);
s2.insert(sum[x-1]);
printf("%lld\n",*(--s2.end()));
}
else{
int h1,h2;
auto it = s1.upper_bound(x);
if(it == s1.end()){
h2 = n;
h1 = *(--it);
}
else{
h2 = *it - 1;
if(it == s1.begin()) h1 = 0;
else h1 = *(--it);
}
s1.insert(x);
s2.insert(sum[h2] - sum[x]);
s2.insert(sum[x-1] - sum[h1]);
s2.erase(s2.find(sum[h2] - sum[h1]));
printf("%lld\n",*(--s2.end()));
}
}
return 0;
}
【解法2】离线+带权并查集,考虑到在线删除比较麻烦,我们可以倒着来把元素加到原来的序列里面并维护最大的连续和,这个用并查集可以做。每一次判断他的前一个以及后一个是否被加进来,合并集合,更新答案即可。
【代码君】
const int maxn = 1e6+10;
long long a[maxn],ans[maxn],s[maxn];
int p[maxn],vis[maxn],fa[maxn],n;
void init(){
memset(vis,false,sizeof(vis));
for(int i = 1; i <= n; i++) fa[i] = i;
}
int Find(int x){
if(x == fa[x]) return x;
return fa[x] = Find(fa[x]);
}
int main()
{
scanf("%d",&n);
for(int i = 1; i <= n; i++) scanf("%lld",&a[i]);
for(int i = 1; i <= n; i++) scanf("%d",&p[i]);
init();
ans[n] = 0;
for(int i = n; i > 1; i--){
int now = p[i];
s[now] = a[now];
if(vis[now-1]){
int x = Find(now),y = Find(now-1);
fa[x] = y;
s[y] += s[x];
}
if(vis[now+1]){
int x = Find(now),y = Find(now+1);
fa[x] = y;
s[y] += s[x];
}
ans[i-1] = max(ans[i],s[Find(now)]);
vis[now] = 1;
}
for(int i = 1; i <= n; i++) printf("%lld\n",ans[i]);
}
【D】一个数x,可以变成2x,或者变成2x+1,可以变化若干次,现在给你n个不同的数Y,你需要找到n个不同的x,使得这n个不同的x经过变化之后,能够得到Y数组,你要使得最初的最大值最小。输出n个不同的x。
【解题方法】贪心,每次选择最大的数,然后使得最大数变小即可,能变就变,用一个set去维护就好了。
【代码君】
set<int>S;
int main()
{
int n,x;
scanf("%d",&n);
for(int i = 1; i <= n; i++){
scanf("%d",&x);
S.insert(-x);
}
while(1)
{
int x = -*S.begin();
int k = *S.begin();
x /= 2;
while(x)
{
if(S.find(-x) == S.end()){
S.insert(-x);
break;
}
x >>= 1;
}
if(x == 0){
for(auto it = S.begin(); it != S.end(); it++){
cout<< -*it <<" ";
}
return 0;
}
S.erase(k);
}
return 0;
}