2022/2/28个人训练
2022/2/28个人训练
A. AquaMoon and Strange Sort
题目大意:
给一个序列a,一开始每个元素都朝右边,可以交换若干次相邻元素。元素经过交换后朝向会改变。问能不能操作出一个非降序序列并且所有元素都朝右。
思路和代码:
首先,为使最后的序列所有元素都朝向右边,需要每个元素都交换偶数次。这就意味着奇数位还是在奇数位,偶数位还是在偶数位。所以我们将奇数位和偶数位分开排序,再在最后合并,判断是否非降序即可。
string solve(){
cin >> n ;
VLL a , odd , eve ;
rep(i , 1 , n){
ll tmp ; cin >> tmp ;
if(i & 1) odd.pb(tmp) ;
else eve.pb(tmp) ;
}
sort(odd.begin() , odd.end()) ;
sort(eve.begin() , eve.end()) ;
ll iod = 0 , iev = 0 , idx = 1 ;
while(idx <= n){
if(idx & 1) a.pb(odd[iod ++ ]) ;
else a.pb(eve[iev ++ ]) ;
idx ++ ;
}
rep(i , 0 , n - 2){
if(a[i] > a[i + 1]) return "NO\n" ;
}return "YES\n" ;
}//code_by_tyrii
小结:
这个方法就很妙,当时我做的时候想的是每个元素都需要交换偶数次。没有想到交换偶数次之后奇数还是奇数,偶数还是偶数。
A. And Matching
题目大意:
有0~n-1的n个数字,每个数字只用一次,两两配对后是否有可能满足以下等式,若能则输出一种配对方法;若不能则输出-1。
$$
\sum_{i=1}^{n/2}a_i&b_i = k
$$
思路和代码:
从0开始思考,i和n-1-i匹配就能将所有的pair做成0,这样总和就是0。若k属于0~n-3,则我们就不让n-1和0配对,而是让k和n-1配对。让n-k-1和0配对。
当k等于n-2时,就凑一下,凑出和为n-1 。
void solve(){
cin >> n >> m ;
if(n == 4 && m == 3){
cout << "-1\n" ; return ;
}
if(m == n - 1){
cout << n - 1 << " " << n - 2 << "\n" ;
cout << n - 3 << " 1\n" ;
cout << "0 2\n" ;
rep(i , 3 , (n + 1) / 2 - 1)
cout << i << " " << n - 1 - i << "\n" ;
return ;
}
rep(i , 1 , (n + 1) / 2 - 1){
ll j = n - 1 - i ;
if(i == m){
cout << i << " " << n - 1 << "\n" ;
cout << 0 << " " << j << "\n" ;
}else if(j == m){
cout << j << " " << n - 1 << "\n" ;
cout << 0 << " " << i << "\n" ;
}else cout << i << " " << j << "\n" ;
}
if(!m){
cout << n - 1 << " 0\n" ;
}//debug ;
}//code_by_tyrii
Codeforces Round #727
打了一场年代久远的比赛的VP啊,说实话第一题是真的...1000分卡了我一整场。我怎么就水平这么烂啊草了。
但是难受归难受,题解还是得写。
A. Contest Start
题目大意:
有n个人,每个人速度相同。第一个人在第0秒出发。每个人耗时t秒就能到终点。每两个人出发时间相隔x秒。一个人的权值是他到终点时,已经出发但是还没有到终点的人的数量。
求n个人的权值和。
思路和代码:
讲道理,我一开始想的是第i个人的权值应该是在第i个人抵达终点的时刻((i-1)x+t)已经出发的人的数量减去已经到达的人的数量。最后求和,即:
$$
ans=min(n-1,t/x)+\sum_{2}^{n}min(n-1,(t+(i-1)x)/t)+1-i
$$
void solve(){
cin >> n >> m >> k ;
ll ans = min(n - 1 , k / m) ;
rep(i , 2 , n){debug ;
ans += min((k + (i - 1) * m) / m + 1 , n) - i ;
cout << ans << "\n" ;
}
cout << ans << "<=\n" ;
}//code_by_tyrii
然后化简一下这个式子让他从O(n)变成O(1)。但是并没有用。
正解是,只要(i-1)*x+t<=(n-1)*x,第i个人的权值就都是t/x 。若超出了,就是t/x-1到0的等差数列。
其实这个结论只要画了0,x,2x,3x,...,(n-1)x的时间图就很容易就能得出。但是我没有画...为什么我就想不到那里去呢...可能是题做的太少了吧....
void solve2(){
ll n , x , t ;
cin >> n >> x >> t ;
ll seg = t / x , ans = 0 ;
if(seg >= n){
ll x = min(seg , n) ;
ans = (x * (x - 1)) / 2 ;
}else{
ans += (seg - 1) * seg / 2 ;
ans += seg * (n - seg) ;
}
cout << ans << "\n" ;
}
小结:
虽然很沮丧,但是这道题暴露出我的问题:
数学薄弱。如果我能化简我第一种想法的式子,这题至少能A,就是没那么快。
思路奇怪。我没有选择去画图,而是去推导了数学式子...什么nt才会这样啊。但是这是有原因的,可能是受到了这道题的影响:传送门。做了这道题我就感觉推数学式子贼帅,可能就下意识地去推导了,但是没有必要。题目没有给式子还是不要自讨苦吃了。
简单问题复杂化。这是我很容易犯的一个错误。我很容易就用一些数据结构去模拟题目的意思,而不是去寻找题目的性质。
B. Love Song
题目大意:
一个串,该字母是字母表里的第几个就要重复几次。给若干段区间,求这段区间里字母重复后的长度。
思路:
这题简单前缀和即可。
ll n , m , k ;
ll p[N] ;
string s ;
void solve(){
ll l , r ; cin >> l >> r ;
cout << p[r] - p[l - 1] << "\n" ;
}//code_by_tyrii
int main(){
ios::sync_with_stdio(false) ;
//cin.tie(0) ; cout.tie(0) ;
//freopen("in.in" , "r" , stdin) ;
cin >> n ;
ll T ; cin >> T ;
cin >> s ;
rep(i , 1 , n) p[i] = p[i - 1] + s[i - 1] - 'a' + 1 ;
while(T -- ) solve() ;
}
C. Stable Groups
题目大意:
给长度为n的一个数组a,要求对a排序后分成ans个子段(不重复)。并且每个字段的相邻元素只差不超过x。当然,最多可以插入k个任意数字。问最少可以分成几个字段。
思路和代码:
水题,排序后将断点的差值放到新数列中,从小到大去补。值得注意的是,x=4,a=[21,30]这样,x可以整除差值的时候,插入数量要少一个。
void solve(){
cin >> n >> m >> k ;
VLL a(n , 0) ;
rep(i , 0 , n - 1) cin >> a[i] ;
sort(a.begin() , a.end()) ;
VLL b ;
//show1(a , 0 , n - 1) ;
ll ans = 1 ;
rep(i , 1 , n - 1){
if(a[i] - a[i - 1] > k){
b.pb(a[i] - a[i - 1]) ;
ans ++ ;
}
}
sort(b.begin() , b.end()) ;
//if(k != 0)
if(b.size() && k != 0)
rep(i , 0 , b.size() - 1){
if((b[i] % k == 0 && b[i] / k - 1 <= m) || (b[i] % k != 0 && b[i] / k <= m)){
ans -- ;
m -= (b[i] % k == 0 ? b[i] / k - 1 : b[i] / k) ;//这里判断一下
}else break ;
}cout << ans << "\n" ;
}//code_by_tyrii
总结:
第一天加训,暴露出了很多问题,刷题真的是真的是太少了。明天继续,时间不早了,先睡了。

浙公网安备 33010602011771号