昨天本來想打一下,但是今天早上課很早,就沒有打,只是看了看前三個題寫了個代碼,今天中午課結束交了一下都AC了。y1s1 A題第一次寫就出來了,但是答案一直不對,最后結果是樣例錯了-。-
 
A - Buying Torches
 
數學題,最終需要stick的數量是ky+kky+kky+k,然后直接求答案就行了。
 
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std
;
typedef long long ll
;
const int N
=100010;
int main()
{IO
;int T
=1;cin
>>T
;while(T
--){ll x
,y
,k
;cin
>>x
>>y
>>k
;ll res
=k
+(1ll*k
*y
+k
-1+x
-2)/(x
-1);cout
<<res
<<endl
;}return 0;
}
 
B - Negative Prefixes
 
對于不固定位置的數,前面越大越好。把不固定位置的數逆序排列,然后插入原數組即可。
 
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std
;
const int N
=100010;
int a
[N
],n
;
bool st
[N
];
int main()
{IO
;int T
=1;cin
>>T
;while(T
--){cin
>>n
;for(int i
=1;i
<=n
;i
++) cin
>>a
[i
];vector
<int> b
;for(int i
=1;i
<=n
;i
++){st
[i
]=0;cin
>>st
[i
];if(!st
[i
]) b
.push_back(a
[i
]);}sort(b
.begin(),b
.end());reverse(b
.begin(),b
.end());for(int i
=1,j
=0;i
<=n
;i
++){if(st
[i
]) cout
<<a
[i
]<<' ';else cout
<<b
[j
++]<<' ';}cout
<<'\n';}return 0;
}
 
C - Mortal Kombat Tower
 
寫個dp考慮轉移即可。
 f[i][1/2][0/1]f[i][1/2][0/1]f[i][1/2][0/1]表示為考慮前iii個boss,最后一次kill殺了1/2個boss,現在是輪到誰了(0表示朋友,1表示自己)。
 轉移就很容易,邊界是f[0][1/2][1]=0f[0][1/2][1]=0f[0][1/2][1]=0由于朋友先手,最開始只能從前面的邊界進行轉移。
 
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std
;
typedef long long ll
;
typedef pair
<ll
,ll
> pll
;
typedef pair
<int,int> pii
;
const int N
=200010;
int a
[N
],n
;
int f
[N
][3][2];
int main()
{IO
;int T
=1;cin
>>T
;while(T
--){cin
>>n
;for(int i
=1;i
<=n
;i
++){cin
>>a
[i
];for(int j
=1;j
<=2;j
++)for(int k
=0;k
<=1;k
++)   f
[i
][j
][k
]=0x3f3f3f3f;}f
[0][2][0]=f
[0][1][0]=0x3f3f3f3f;for(int i
=1;i
<=n
;i
++){f
[i
][1][0]=min(f
[i
-1][1][1],f
[i
-1][2][1])+a
[i
];if(i
>=2) f
[i
][2][0]=min(f
[i
-2][1][1],f
[i
-2][2][1])+a
[i
]+a
[i
-1];f
[i
][1][1]=min(f
[i
-1][1][0],f
[i
-1][2][0]);if(i
>=2) f
[i
][2][1]=min(f
[i
-2][1][0],f
[i
-2][2][0]);}int res
=0x3f3f3f3f;for(int i
=1;i
<=2;i
++)for(int j
=0;j
<=1;j
++)res
=min(res
,f
[n
][i
][j
]);cout
<<res
<<'\n';}return 0;
}
 
D - Trash Problem
 
貪心:我們只要把所有坐標先排序,然后只找出兩個相距最遠的兩堆垃圾,然后分別向左和向右知道最左端和最右端所移動的步數就是答案。
 比如排序后最左端的垃圾左邊是lll,最右端是rrr,這些垃圾中u,vu,vu,v相距最遠距離是ddd,那么答案就是r?l?dr-l-dr?l?d
 考慮需要維護的哪些東西?
 首先維護垃圾位置并且每次支持排序只需要用set維護即可
 齊次需要維護每對垃圾之間的距離,由于可能出現重復序列我們用multiset維護即可。
 每次某位置加入一個垃圾或者刪除某位置的垃圾就維護一下set和multiset即可。
 
關于multiset的ms.erase(x)
 如果xxx是值,那么它將刪除所有val=xval=xval=x,如果xxx是地址,將刪除該地址的數,因此如果想要只刪除一個val=xval=xval=x的數,需要先找到地址,然后按照地址刪除。
 
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<iostream>
#include<algorithm>
using namespace std
;
typedef long long ll
;
typedef pair
<ll
,ll
> pll
;
typedef pair
<int,int> pii
;
const int N
=100010;
set
<int> s
;
multiset
<int,greater
<int>> ms
; 
int n
,q
;
int a
[N
];
int main()
{IO
;int T
=1;while(T
--){cin
>>n
>>q
;for(int i
=1;i
<=n
;i
++) {cin
>>a
[i
];s
.insert(a
[i
]);}sort(a
+1,a
+1+n
);ms
.insert(0);for(int i
=2;i
<=n
;i
++) ms
.insert(a
[i
]-a
[i
-1]);for(int i
=0;i
<=q
;i
++){if(s
.size()<=2) cout
<<"0\n";else{auto ed
=s
.end();ed
--;int l
=*s
.begin(),r
=*ed
;cout
<<r
-l
-*ms
.begin()<<'\n';}if(i
!=q
){int op
,x
;cin
>>op
>>x
;if(op
==1){s
.insert(x
);if(s
.size()==1) continue;auto ed
=s
.end();ed
--;auto t
=s
.find(x
);if(t
==ed
){t
--;ms
.insert(x
-*t
);}else if(t
==s
.begin()){t
++;ms
.insert(*t
-x
);}else{auto t1
=t
,t2
=t
;t1
--;t2
++;ms
.insert(*t2
-x
);ms
.insert(x
-*t1
);auto p
=ms
.find(*t2
-*t1
);ms
.erase(p
);}}else{if(s
.size()==1){s
.erase(x
);continue;}auto t
=s
.find(x
);auto ed
=s
.end();ed
--;if(t
==ed
){t
--;auto p
=ms
.find(x
-*t
);ms
.erase(p
);}else if(t
==s
.begin()){t
++;auto p
=ms
.find(*t
-x
);ms
.erase(p
);}else{auto t1
=t
,t2
=t
;t1
--;t2
++;ms
.insert(*t2
-*t1
);auto p1
=ms
.find(x
-*t1
);ms
.erase(p1
);auto p2
=ms
.find(*t2
-x
);ms
.erase(p2
);}s
.erase(x
);}}}}return 0;
}
 
由于自己對STL不是太熟悉,踩了非常多的坑www
 一位網友的set總結
 
剩下的題以后再看吧?可能?
 
E - Expected Damage
 
首先我們讓d≥bd \ge bd≥b的怪物稱為大怪物,否則稱為小怪物。
 不難發現:如果大怪物的個數big<abig<abig<a,那么所有怪物都不會造成傷害,否則才能造成傷害。
 小怪物的位置并不會影響大怪物是否造成傷害,不過大怪物的位置會影響小怪物是否造成傷害,因此我們先考慮大怪物的位置。如果一個大怪物想要造成傷害那么它的前面一定有aaa個大怪物,也就是說他只要不是前面aaa個大怪物(炮灰)他就能造成傷害,共有bigbigbig個大怪物那么他不是前aaa個怪物的概率是1?abig1-\frac{a}{big}1?biga?,現在把所有大怪物排列好,那么一共有big+1big+1big+1個空位可以放置小怪物(由于小怪物直接互不影響,每個位置可以放置隨意多個小怪物),小怪物想要造成傷害它的位置一定在前aaa的大怪物后面,易求概率為1?abig+11-\frac{a}{big+1}1?big+1a?,由此預處理前綴和,然后快速冪逆元即可得到答案。
 
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std
;
typedef long long ll
;
const int N
=200010,mod
=998244353;
int d
[N
],s
[N
];
int n
,m
;
int qmi(int a
,int b
,int p
)
{int res
=1;while(b
){if(b
&1) res
=1ll*res
*a
%p
;a
=1ll*a
*a
%p
;b
>>=1;}return res
;
}
int main()
{IO
;int T
=1;while(T
--){cin
>>n
>>m
;for(int i
=1;i
<=n
;i
++) cin
>>d
[i
];sort(d
+1,d
+1+n
);for(int i
=1;i
<=n
;i
++) s
[i
]=(s
[i
-1]+d
[i
]%mod
)%mod
;while(m
--){int a
,b
;cin
>>a
>>b
;int pos
=lower_bound(d
+1,d
+1+n
,b
)-d
;int small
=pos
-1,big
=n
-pos
+1;int res
;if(big
<a
) res
=0;elseres
=(1ll*(big
+1-a
)*qmi(big
+1,mod
-2,mod
)%mod
*s
[small
]%mod
+1ll*(big
-a
)*qmi(big
,mod
-2,mod
)%mod
*(s
[n
]-s
[small
]+mod
)%mod
)%mod
;cout
<<res
<<'\n';}}return 0;
}
 
要加油哦~
                            總結
                            
                                以上是生活随笔為你收集整理的Educational Codeforces Round 95 (Rated for Div. 2)的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                            
                                如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。