比赛链接:https://codeforces.com/contest/1654
C. Alice and the Cake
题意
有一块蛋糕经过下面
n
−
1
n-1
n−1 次操作被切成了
n
n
n 块:
- 选择一块重量 w ≥ 2 w\ge 2 w≥2 的蛋糕,将其切成两块重量分别为 ⌊ w 2 ⌋ \lfloor\frac{w}{2}\rfloor ⌊2w⌋ 和 ⌈ w 2 ⌉ \lceil\frac{w}{2}\rceil ⌈2w⌉ 的小蛋糕。
现在给定最终的
n
n
n 块小蛋糕,判断其是否能由上面的操作得到?
1
≤
n
≤
2
⋅
1
0
5
,
1
≤
a
i
≤
1
0
9
1 \le n \le 2 \cdot 10^5, \ 1 \le a_i \le 10^9
1≤n≤2⋅105, 1≤ai≤109
思路
一开始一直在想,到底怎么合并,依次哪两个合并能把所有的合并成一个。。
想了几种策略之后发现都不行,被卡住。。
后面又想,它反正能合并成一个,是由一个切出来的,那么不妨就从最初始的一个往后分,如果分出的一块在数列中出现过,那就把数列中的这个消掉,最后判断数列中的所有数是否都消掉就行了。
Code
#include<bits/stdc++.h>
using namespace std;
#define Ios ios::sync_with_stdio(false),cin.tie(0)
const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N];
signed main(){
Ios;
cin >> T;
while(T--)
{
mp.clear();
cin >> n;
m = 0;
for(int i=1;i<=n;i++){
cin >> a[i];
m += a[i];
mp[a[i]]++;
}
stack<int> stk;
stk.push(m);
int flag = 0;
while(n)
{
int x = stk.top(); stk.pop();
if(mp[x]) mp[x]--, n--;
else
{
int t1, t2;
if(x % 2 == 0) t1 = t2 = x/2;
else t1 = x/2, t2 = x/2+1;
if(!t1){
flag = 1;
break;
}
stk.push(t1);
stk.push(t2);
}
}
if(flag) cout << "NO\n";
else cout << "YES\n";
}
return 0;
}
经验
既然是思维题,那就不能从正常的思路去想,及时的转换思路很关键!从不寻常的思路去考虑!
B. Prefix Removals
题意
给定一个长度为 n 的小写字母串,输出执行过下面的操作后剩下的字符串:
- 选择最长的一个满足后面要求的前缀,该前缀满足在串中的其他地方也要作为子串出现(可以与前缀串有交叉);
- 在字符串中删除该前缀串;
- 重复以上过程,直到找不到满足的前缀串。
n ≤ 2 ⋅ 1 0 5 n \le 2 \cdot 10^5 n≤2⋅105
思路
6
abcabdc
a
bbbbbbbbbb
codeforces
cffcfccffccfcffcfccfcffccffcfccf
zyzyzwxxyyxxyyzzyzzxxwzxwywxwzxxyzzw
abdc
a
b
deforces
cf
xyzzw
根据样例发现,没必要每次找最长的前缀,只需要看首个字符就行了:
- 如果这个字符在后面的位置出现过,那么这个字符就可以删去;
- 否则输出剩下的串。
字符串长度要求 O(n) 的复杂度,那么标记出每个字符最后一次出现的位置就行了,每次判断其出现的位置是否在当前位置之后。
Code
#include<bits/stdc++.h>
using namespace std;
#define Ios ios::sync_with_stdio(false),cin.tie(0)
const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N], p[N];
signed main(){
Ios;
cin >> T;
while(T--)
{
for(int i=0;i<26;i++) p[i] = 0;
string s; cin >> s;
for(int i=0;i<s.size();i++)
{
p[s[i]-'a'] = i;
}
int st = 0;
for(int i=0;i<s.size();i++)
{
if(p[s[i]-'a'] <= i){
st = i;
break;
}
}
for(int i=st;i<s.size();i++) cout << s[i];
cout << endl;
}
return 0;
}