前言:单人写了一下,只写出了4题,大概铜中的水准。疯狂wawawa。
D. Bits Reverse
题目类型:二进制、位运算
解析: ABC倒置为CBA其实就是隔一位交换、那么奇数位可以互换、偶数位可以互换;分别看一下奇偶位1数量是否一样,然后贪心取。
code:
#include <bits\stdc++.h>
#define Lnnnb return 0;
#define ll long long
#define mem(a) memset(a,0,sizeof(a))
#define maxn 202020
using namespace std;
void eninit();
ll n,x,y,ttt;
ll xnt,ynt,xon[70],yon[70];
void finit(){
}
void scan(){
cin >> x >> y ;
}
ll add(ll ned){
xnt = ynt = 0;
ll m = x , res = 0;
for(ll i = 1 ; m ; ++i , m /= 2){
if(i%2 == ned && m%2 == 1)xon[++xnt] = i;
}
m = y;
for(ll i = 1 ; m ; ++i , m /= 2){
if(i%2 == ned && m%2 == 1)yon[++ynt] = i;
}
if(xnt != ynt)return -1;
for(ll i = 1 ; i <= xnt ; ++i){
res += abs(xon[i] - yon[i])/2;
}
return res;
}
void solve(){
ll res1 = 0 , res0 = 0;
res1 = add(1);
res0 = add(0);
if(res1 == -1 || res0 == -1){
cout << "Case " << ttt << ": " << -1 << endl ;
return;
}
cout << "Case " << ttt << ": " << res1 + res0 << endl ;
}
int main(){
ios::sync_with_stdio(false);
///cin.tie(0);cout.tie(0);
finit();
ll t = 1;
cin >> t ;
for(ttt = 1 ; ttt <= t ; ++ttt){
scan();
solve();
eninit();
}
Lnnnb
}
void eninit(){
}
H. Hamming Distance
题目类型:字符串、字典序、贪心
解析:因为字典序最小、尽量从前面贪心。如果两个位置字符一样,那就直接放a;不一样的单独处理,从前向后,看看后面的不同位置够不够将汉明距离变为0,够就放a,刚好就放b或者c,不够就只能补给汉明距离大的字符串。
code:
#include <bits\stdc++.h>
#define Lnnnb return 0;
#define ll long long
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define maxn 1010101
using namespace std;
void eninit();
ll n,ttt,dif[maxn];
char a[maxn],b[maxn],s[maxn];
void finit(){
}
void scan(){
cin >> a+1 ;
cin >> b+1 ;
n = strlen(a+1);
}
void solve(){
ll dnt = 0 , lval = 0 , rval = 0;
for(ll i = 1 ; i <= n ; ++i){
if(a[i] == b[i])s[i] = 'a';
else {
dif[++dnt] = i;
}
}
for(ll iii = 1 ; iii <= dnt ; ++iii){
ll x = dif[iii];
if(a[x] != 'a' && b[x] != 'a'){
if(abs(lval-rval) <= dnt - iii){
s[x] = 'a';
}else {
if(lval > rval){
s[x] = a[x];
rval++;
}else {
s[x] = b[x];
lval++;
}
}
}else {
a[x] == 'a' ? rval++ : lval++ ;
if(abs(lval-rval) <= dnt - iii){ ///只要差值<=剩下的不同的
s[x] = 'a';
}else {
a[x] == 'a' ? rval-- : lval--; ///先不取a
if(abs(lval-rval) == dnt - iii){ ///保持不变
if(a[x] != 'b' && b[x] != 'b'){
s[x] = 'b';
}else {
if(lval > rval && a[x] == 'b')s[x] = 'b' , rval++;
else if(lval < rval && b[x] == 'b')s[x] = 'b' , lval++;
else s[x] = 'c';
}
}else { ///差太大了
if(lval > rval){
s[x] = a[x];
rval++;
}else {
s[x] = b[x];
lval++;
}
}
}
}
}
cout << "Case " << ttt << ": " << s+1 ;
}
///cout << "Case " << ttt << ": " << ;
int main(){
ios::sync_with_stdio(false);
///cin.tie(0);cout.tie(0);
finit();
ll t = 1;
cin >> t ;
for(ttt = 1 ; ttt <= t ; ++ttt){
scan();
solve();
eninit();
if(ttt != t)cout << endl ;
}
Lnnnb
}
void eninit(){
for(ll i = 0 ; i <= n+10 ; ++i){
a[i] = b[i] = s[i] = 0;
}
}
G. Greatest Common Divisor
题目类型:gcd、差分
解析:(应该能很自然的想到差分数组不变把 )为什么差分呢:想象一下,将数组排序后,假设差分数组的gcd = g。那么只要a1是g的倍数,a[i] = a[1]+k*g,就都是g的倍数。g的因子同理,所以就枚举g的因子yz,看看a1变为yz需要加多少次即可。
code:
#include <bits\stdc++.h>
#define Lnnnb return 0;
#define ll long long
#define mem(a) memset(a,0,sizeof(a))
#define maxn 202020
using namespace std;
void eninit();
ll n,ttt;
ll a[maxn];
ll gcd(ll aa,ll bb){
return bb == 0 ? aa : gcd(bb,aa%bb);
}
void finit(){
}
void scan(){
cin >> n ;
for(ll i = 1 ; i <= n ; ++i){
cin >> a[i] ;
}
}
void solve(){
sort(a+1,a+1+n);
ll g = 0 , ji = 1;
for(ll i = 1 ; i <= n ; ++i){
g = gcd(g , a[i]);
if(a[i]%2 == 0)ji = 0;
}
if(g > 1){
cout << "Case " << ttt << ": " << 0 << endl ;
return;
}
if(ji){
cout << "Case " << ttt << ": " << 1 << endl ;
return;
}
ll cha = 0;
for(ll i = 1 ; i <= n-1 ; ++i){
if(a[i+1] - a[i] == 0)continue;
cha = gcd(cha , a[i+1] - a[i]);
}
if( cha == 1 ){
cout << "Case " << ttt << ": " << -1 << endl ;
return;
}
ll ans = 4e18;
for(ll i = 2 ; i*i <= cha ; ++i){
if(cha %i == 0){
ll x = i , y = cha/i;
ans = min(ans , (x - a[1]%x)%x );
ans = min(ans , (y - a[1]%y)%y );
}
}
ans = min(ans , (cha - a[1]%cha)%cha );
cout << "Case " << ttt << ": " << ans << endl ;
}
int main(){
ios::sync_with_stdio(false);
///cin.tie(0);cout.tie(0);
finit();
ll t = 1;
cin >> t ;
for(ttt = 1 ; ttt <= t ; ++ttt){
scan();
solve();
eninit();
}
Lnnnb
}
void eninit(){
}
J. Stone Game
题目类型:博弈、拓扑排序
解析:此题胜负完全不由决策决定。因为相邻的数不相同,所以总会有a[i]满足a[i-1] > a[i] && a[i+1] > a[i],那么a[i]就可以变为0。
这个数组相当于相邻的数有一条边,小的指向大的数,一个有向无环图,所以比两边都小的加入队列,逐步减少其他点的入度,拓扑排序一下即可。
比如:2 3 4 1
第一个数和第四个数可以变成0:0 3 4 0
第二个数变成1:0 1 4 0
第三个数变成2:0 1 2 0
计算新数组和原来数组的差值和,奇数A赢,偶数B赢。
code:
#include <bits\stdc++.h>
#define Lnnnb return 0;
#define ll long long
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define maxn 1010101
using namespace std;
void eninit();
ll n,ttt;
ll a[maxn],c[maxn],vis[maxn];
queue<ll>q;
void finit(){
}
void scan(){
cin >> n ;
for(ll i = 1 ; i <= n ; ++i){
cin >> a[i] ;
}
}
ll check(ll i){
ll lf = (a[i-1] > a[i] || vis[i-1]);
ll rg = (a[i+1] > a[i] || vis[i+1]);
return (lf && rg);
}
void solve(){
ll sum = 0;
a[0] = a[n+1] = 1e9;
vis[0] = vis[n+1] = 1;
for(ll i = 1 ; i <= n ; ++i){
if(a[i-1] > a[i] && a[i] < a[i+1] && !vis[i]){
q.push(i);
}
}
while(!q.empty()){
ll top = q.front();
q.pop();
vis[top] = 1;
ll l = top-1 , r = top+1;
if(!vis[l] && check(l)){
vis[l] = 1;
q.push(l);
c[l] = max(c[l-1] , c[l+1]) + 1;
}
if(!vis[r] && check(r)){
vis[r] = 1;
q.push(r);
c[r] = max(c[r-1] , c[r+1]) + 1;
}
}
for(ll i = 1 ; i <= n ; ++i){
sum += (a[i] - c[i]);
}
if(sum%2 == 1)cout << "Case " << ttt << ": " << "Alice" ;
else cout << "Case " << ttt << ": " << "Bob" ;
}
///cout << "Case " << ttt << ": " << ;
int main(){
ios::sync_with_stdio(false);
///cin.tie(0);cout.tie(0);
finit();
ll t = 1;
cin >> t ;
for(ttt = 1 ; ttt <= t ; ++ttt){
scan();
solve();
eninit();
if(ttt != t)cout << endl ;
}
Lnnnb
}
void eninit(){
for(ll i = 0 ; i <= n+10 ; ++i){
c[i] = vis[i] = 0;
}
}
A. Array Merge
题目类型:单调栈、相邻比较法、连续序列平均值
解析:想一下,最后的序列肯定是AA…B…A…B…
并且要分别维护A、B数组在原序列的顺序,考虑相邻比较法,可以交换相邻的一段A和一段B。
交换后的变化以及具体式子见大佬博客
然后用单调栈维护(连续序列平均值)的递减
code:
#include <bits\stdc++.h>
#define Lnnnb return 0;
#define ll long long
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define maxn 202020
using namespace std;
void eninit();
ll nnn,mmm,ttt;
ll snt,sat,sbt,aaa[maxn],bbb[maxn];
struct seg{
ll sum,l,r,len;
}st[maxn],saa[maxn],sbb[maxn];
///单调栈合并递减平均子序列
void merge_(ll *a,ll len,seg *s,ll &lennnn){
snt = 0;
for(ll i = 1 ; i <= len ; ++i){
if(!snt || st[snt].sum > a[i]*(st[snt].len)){
st[++snt] = {a[i] , i , i , 1};
}else {
st[snt].sum += a[i];
st[snt].r = i;
st[snt].len++;
while(snt >= 2 && st[snt].sum*st[snt-1].len >= st[snt-1].sum*st[snt].len ){
st[snt-1] = {st[snt].sum+st[snt-1].sum , st[snt-1].l , st[snt].r , st[snt].len+st[snt-1].len};
--snt;
}
}
}
for(ll i = 1 ; i <= snt ; ++i)s[i] = st[i];
lennnn = snt;
}
ll coun(ll *a,ll hav,ll l,ll r){
ll res = 0;
for(ll i = l , num = 1 ; i <= r ; ++i , ++num){
res += a[i] * (hav + num);
}
return res;
}
void finit(){
}
void scan(){
cin >> nnn >> mmm ;
for(ll i = 1 ; i <= nnn ; ++i)cin >> aaa[i] ;
for(ll i = 1 ; i <= mmm ; ++i)cin >> bbb[i] ;
}
void solve(){
merge_(aaa,nnn,saa,sat);
merge_(bbb,mmm,sbb,sbt);
ll l = 1 , r = 1 , hav = 0 , ans = 0;
while(l <= sat && r <= sbt){
if(saa[l].sum*sbb[r].len >= sbb[r].sum*saa[l].len){
ans += coun(aaa,hav,saa[l].l , saa[l].r);
hav += saa[l++].len;
}else {
ans += coun(bbb,hav,sbb[r].l , sbb[r].r);
hav += sbb[r++].len;
}
}
while(l <= sat){
ans += coun(aaa,hav,saa[l].l , saa[l].r);
hav += saa[l++].len;
}
while(r <= sbt){
ans += coun(bbb,hav,sbb[r].l , sbb[r].r);
hav += sbb[r++].len;
}
cout << "Case " << ttt << ": " << ans ;
}
///cout << "Case " << ttt << ": " << ;
int main(){
ios::sync_with_stdio(false);
///cin.tie(0);cout.tie(0);
finit();
ll t = 1;
cin >> t ;
for(ttt = 1 ; ttt <= t ; ++ttt){
scan();
solve();
eninit();
if(ttt != t)cout << endl ;
}
Lnnnb
}
void eninit(){
}
总结
1.字典序还是要直接从前面考虑,不知道写H的时候怎么想的,整了个前后指针,debug了半天。
2.输出格式,还有不常见的数组大小开大点。。。