Codeforces Round 1005 (Div. 2) A-D题解

A. Brogramming Contest

主要就是统计一下最后一个0移动了多少次就行了(和他前面的1联通块数量有关)

总体时间复杂度O(n)

AC

// Problem: A. Brogramming Contest
// Contest: Codeforces - Codeforces Round 1005 (Div. 2)
// URL: https://codeforces.com/contest/2064/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// by znzryb
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define all(x) x.begin(), x.end()
#define CLR(i, a) memset(i, a, sizeof(i))
#define fi first
#define se second
#define pb push_back
#define SZ(a) ((int)a.size())

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
typedef array<ll, 3> arr;
typedef double DB;
typedef pair<DB, DB> pdd;
constexpr ll MAXN = static_cast<ll>(1e3) + 10, INF = static_cast<ll>(5e18) + 3;

ll N, M, T;
char A[MAXN];

inline void solve() {
  cin >> N;
  FOR(i, 1, N) { cin >> A[i]; }
  ll ans = 0;
  bool isConti0 = false, isConti1 = false,flag=false;
  ROF(i, N, 1) {
    if (A[i] == '0' && !isConti0) {
      isConti0 = true, isConti1 = false;
      if(!flag){
      	ll cnt = 0;
	      bool isConti = false;
	      ROF(j, i - 1, 1) {
	        if (A[j] == '1' && !isConti) {
	          ++cnt, isConti = true;
	        } else if (A[j] == '0') {
	          isConti = false;
	        }
	      }
	      ans += cnt;
	      flag=true;
      }
    } else if (A[i] == '1' && !isConti1) {
      isConti0 = false, isConti1 = true;
      ++ans;
    } else if (A[i] == '0' && isConti0) {
      isConti0 = true, isConti1 = false;
    } else if (A[i] == '1' && isConti1) {
      isConti0 = false, isConti1 = true;
    }
  }
  cout << ans << '\n';
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  cin >> T;
  while (T--) {
    solve();
  }
  return 0;
}
/*
pretest pass 4

*/

B. Variety is Discouraged

其实这种只指定了substring的话,一般都有固定的操作模式,因为把所有l,r都遍历一遍就超时了,所以一般也不可能加速暴力计算

当然你说有没有可能是双指针,这个就需要具体分析了,主要还是这个计算用双指针没那么方便(这种计算没有可加性,不容易合并),所以也不太行

我们容易发现,这个只有删除只出现过一次的元素,才有可能让值保持不变,如果删除了一个重复出现过两次的元素,会直接让值下降,不符合题设

在样例中我们也发现,删除只是会让长度缩短,并不能增加得分
3
1
1
5
1 1 1 1 1
4
2 1 3 2

1 1
0
2 3

AC

// Problem: B. Variety is Discouraged
// Contest: Codeforces - Codeforces Round 1005 (Div. 2)
// URL: https://codeforces.com/contest/2064/problem/B
// Memory Limit: 256 MB
// Time Limit: 1500 ms
// by znzryb
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define all(x) x.begin(), x.end()
#define CLR(i, a) memset(i, a, sizeof(i))
#define fi first
#define se second
#define pb push_back
#define SZ(a) ((int)a.size())

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
typedef array<ll, 3> arr;
typedef double DB;
typedef pair<DB, DB> pdd;
constexpr ll MAXN = static_cast<ll>(2e5) + 10, INF = static_cast<ll>(5e18) + 3;

ll N, M, T, A[MAXN];  // diff[MAXN], ndiff[MAXN],sum[MAXN],nsum[MAXN];
ll cnt[MAXN], pos[MAXN];

inline void solve() {
  cin >> N;
  bool flag = true;
  FOR(i, 1, N) {
    cnt[i] = 0;
    pos[i] = 0;
  }
  FOR(i, 1, N) {
    cin >> A[i];
    if (A[i] != A[i - 1] && i != 1) flag = false;
    // cnt[A[i]] = cnt.find(A[i]) == cnt.end() ? 1 : cnt[A[i]] + 1;
    cnt[A[i]] += 1;
    pos[A[i]] = i;
  }
  // if (flag && N != 1) {
    // cout << 0 << '\n';
    // return;
  // }
  // if (N == 1) {
    // cout << 1 << ' ' << 1 << '\n';
    // return;
  // }
  vector<ll> needDel;
  FOR(i, 1, N) {
    if (cnt[i] == 1) {
      needDel.pb(pos[i]);
    }
  }
  if(needDel.empty()){  // 注意空的判断,不要漏了
  	cout<<0<<'\n';
  	return;
  }
  if (SZ(needDel) == 1) {
    cout << needDel[0] << ' ' << needDel[0] << '\n';
    return;
  }
  sort(all(needDel));
  ll l = needDel[0], r = needDel[0];
  vector<arr> ans;
  FOR(i, 1, SZ(needDel) - 1) {
    ll p = needDel[i], bp = needDel[i - 1];
    if (p - bp == 1) {
      r = p;
    } else {
      ans.pb({r - l, l, r});
      l = p;
      r = p;
    }
  }
  ans.pb({r - l, l, r});
  sort(all(ans));
  cout << ans.back()[1] << ' ' << ans.back()[2] << '\n';
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  cin >> T;
  while (T--) {
    solve();
  }
  return 0;
}
/*
AC
https://codeforces.com/contest/2064/submission/306477034
*/

C. Remove the Ends

我们容易观察到,其实只有正数+负数这种可能,比如负数1+正数+负数2,相当于只选了负数1,正数1+负数+正数2,也相当于只选了正数2

WA

这个WA是因为我没考虑到这里所说的正数,负数是可以不连续的,即为子序列,而不是子串

其实子序列反而好弄一点,用正数前缀和+负数后缀和就搞定了

AC

// Problem: C. Remove the Ends
// Contest: Codeforces - Codeforces Round 1005 (Div. 2)
// URL: https://codeforces.com/contest/2064/problem/C
// Memory Limit: 256 MB
// Time Limit: 3000 ms
// by znzryb
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define all(x) x.begin(),x.end()
#define CLR(i,a) memset(i,a,sizeof(i))
#define fi first
#define se second
#define pb push_back
#define SZ(a) ((int) a.size())

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pll;
typedef array<ll,3> arr;
typedef double DB;
typedef pair<DB,DB> pdd;
constexpr ll MAXN=static_cast<ll>(2e5)+10,INF=static_cast<ll>(5e18)+3;

ll N,M,T,A[MAXN];
ll zsum[MAXN],fsum[MAXN];

inline void solve(){
	// 这是一道有关前后缀最大化得分的题
	// 只有正数+负数这种可能,比如负数1+正数+负数2,相当于只选了负数1
	// 正数1+负数+正数2,也相当于只选了正数2
	// 当然,这些正数是不一定相连的,负数也是同理
	cin>>N;
	zsum[0]=0;
	FOR(i,1,N){
		cin>>A[i];
		if(A[i]>=0){
			zsum[i]=zsum[i-1]+abs(A[i]);
		}else{
			zsum[i]=zsum[i-1];
		}
	}
	fsum[N+1]=0;
	ROF(i,N,1){
		if(A[i]<0){
			fsum[i]=fsum[i+1]+abs(A[i]);
		}else{
			fsum[i]=fsum[i+1];
		}
	}
	ll ans=0;
	FOR(i,0,N){
		ans=max(zsum[i]+fsum[i+1],ans);
	}
	cout<<ans<<'\n';
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}
/*
WA
https://codeforces.com/contest/2064/submission/306518627
这个WA是因为我没考虑到这里所说的正数,负数是可以不连续的,即为子序列,而不是子串
AC
https://codeforces.com/contest/2064/submission/306520956
*/

D. Eating

感觉是一道数据结构+位运算题(当然这两个我都比较一般)

这道题最烦人的其实就是异或计算没有单调性,不是说我这个值满足,比这个值大的都满足

所以说位运算位运算,总归是要按位分析

看了一下题解,总结来说就是(msb可以理解二进制数的位数)

// == msb 通过计算判断能不能吃,msb必定减少
// > msb 吃不了
// < msb 可以吃

因为==msb的这种比较复杂的情况必定会让x的msb下降,

WA

WA的原因是由于lower_bound()方式实现的__lg()有点问题,我们还是老老实实写一个_lg2()吧

AC

// Problem: D. Eating
// Contest: Codeforces - Codeforces Round 1005 (Div. 2)
// URL: https://codeforces.com/contest/2064/problem/D
// Memory Limit: 512 MB
// Time Limit: 5000 ms
// by znzryb
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define all(x) x.begin(),x.end()
#define CLR(i,a) memset(i,a,sizeof(i))
#define fi first
#define se second
#define pb push_back
#define SZ(a) ((int) a.size())

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pll;
typedef array<ll,3> arr;
typedef double DB;
typedef pair<DB,DB> pdd;
constexpr ll MAXN=static_cast<ll>(2e5)+10,INF=static_cast<ll>(5e18)+3;

ll N,M,T,A[MAXN];
ll pow2[40];
ll last[MAXN][35];		// 从后往前,比这位msb大的(包括相等)最大的编号在哪里()
ll sumA[MAXN];

inline int _lg2(ll n) {
    int pos = 0;
    while (n) {
        n >>= 1;
        pos++;
    }
    return pos;
}

inline void solve(){
	cin>>N>>M;
	FOR(i,1,N){
		cin>>A[i];
		ll msb=_lg2(A[i]);
		FOR(j,0,33){
			if(j<=msb){
				last[i][j]=i;
			}else{
				last[i][j]=last[i-1][j];
			}
		}
	}
	sumA[N+1]=0;
	ROF(i,N,1){		// 异或总和
		sumA[i]=sumA[i+1]^A[i];
	}
	// == msb 通过计算判断能不能吃,msb必定减少
	// > msb 吃不了
	// < msb 可以吃
	FOR(i,1,M){
		ll x;
		cin>>x;
		ll msb=_lg2(x);
		ll idx=last[N][msb],upPos=N+1;
		while(idx>0){
			if((x^(sumA[idx+1]^sumA[upPos]))>=A[idx]){
// #ifdef LOCAL
    // cerr<<i<<' ' << idx<<' '<<x<<' '<< A[idx]<<' '<< (x^(sumA[idx+1]^sumA[upPos])) << '\n';
// #endif
				x=( (x^(sumA[idx+1]^sumA[upPos]))^A[idx]);
				msb=_lg2(x);
				upPos=idx;
				idx=last[idx-1][msb];	// 第idx个我已经吃了,那自然要看第idx-1个
			}else{
				// idx=upPos;	
				break;
			}
		}
		cout<<N-idx<<' '; // 第idx个吃不了,但他的idx后面一个位置是可以吃的
	}
	cout<<'\n';
// #ifdef LOCAL
	// FOR(i,1,7){
		// FOR(j,1,N){
			// cerr<<last[j][i]<<' ';
		// }
		// cerr<<'\n';
	// }
// #endif
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>T;
	pow2[0]=1;
	FOR(i,1,38){
		pow2[i]=pow2[i-1]*2;
	}
	while(T--){
		solve();
	}
	return 0;
}
/*
AC
https://codeforces.com/contest/2064/submission/306654531
*/
全部评论

相关推荐

评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务