A. The Man who became a God
题意
给出一个序列,以及要求把这个序列划分为多少段,求这些段中差分数组之和最小为多少
题解
已给出需划分成m段,即要求删去m-1差分数组中的元素,直接排序然后删去最大的
code
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define ll long long
#define NO cout<<"NO"<<endl
#define YES cout<<"YES"<<endl
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int mod = 1e9 + 7;
const int N = 2e6 + 10;
ll inf = (1ll << 60);
//priority_queue <int,vector<int>,less<int> > p;
//priority_queue <int,vector<int>,greater<int> > q;
int a[N],b[N];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T = 1;
cin >> T;
while (T--)
{
int n,k;
cin>>n>>k;
rep(i,1,n) cin>>a[i];
int ans=0;
rep(i,2,n)
{
b[i-1]=abs(a[i]-a[i-1]);
ans+=b[i-1];
}
sort(b+1,b+n);
k--;
for(int i=n-1;i>=1;i--)
{
if(k==0) break;
if(k) ans-=b[i];
k--;
}
cout<<ans<<endl;
}
}
B. Hamon Odyssey
题意
给出一个序列,设该序列被划分为m块,使每块连续取&,每块的值为,在所有
的和最小的情况下求最多的块数
题解
已知a&b<=a,a&b<=b,所以所有数取&一定最小,所有数取&的记为t
若t=0,则只需要找取&后为0的块数
若t>0,则划分成一块即可,可证明没有比这种情况更小的
code
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define ll long long
#define NO cout<<"NO"<<endl
#define YES cout<<"YES"<<endl
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int mod = 1e9 + 7;
const int N = 2e6 + 10;
ll inf = (1ll << 60);
//priority_queue <int,vector<int>,less<int> > p;
//priority_queue <int,vector<int>,greater<int> > q;
int a[N];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T = 1;
cin >> T;
while (T--)
{
int n;
cin>>n;
rep(i,1,n) cin>>a[i];
int t=a[1];
rep(i,1,n) t&=a[i];
if(t!=0)
{
cout<<1<<endl;
continue;
}
int x=a[1];
int ans=0;
rep(i,1,n)
{
x&=a[i];
if(x==0)
{
x=a[i+1];
ans++;
}
}
cout<<ans<<endl;
}
}
C. Vampiric Powers, anyone?
题意
给出一个长度为n的序列a,现在可以选择一个序列下标i,并向序列后添加一个元素,设添加元素为x,则x=a[i]^...a[m] (x为第m+1个元素),问可以添加的最大的x值是什么
题解
题目实际上每次新增的元素都会放在序列末尾,并且无法忽略,所以本质上可以转化为求某一段区间的最大异或和
code
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define ll long long
#define NO cout<<"NO"<<endl
#define YES cout<<"YES"<<endl
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int mod = 1e9 + 7;
const int N = 2e6 + 10;
ll inf = (1ll << 60);
//priority_queue <int,vector<int>,less<int> > p;
//priority_queue <int,vector<int>,greater<int> > q;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T = 1;
cin >> T;
while (T--)
{
int n;
cin >> n;
vector<int>a(n), nums;
rep(i, 0, n - 1) cin >> a[i];
int x = 0;
nums.push_back(0);
rep(i, 0, n - 1)
{
x ^= a[i];
nums.push_back(x);
}
x = 0;
for (int k = 30; k >= 0; --k)
{
unordered_set<int> seen;
for (int num : nums) seen.insert(num >> k);
int x_next = x * 2 + 1;
bool found = false;
for (int num : nums)
{
if (seen.count(x_next ^ (num >> k)))
{
found = true;
break;
}
}
if (found) x = x_next;
else x = x_next - 1;
}
cout << x << endl;
}
}
D. Professor Higashikata
题意
给出字符串s,区间个数m,例如对于字符串100110,区间(1,2),(1,2),(3,4),那么拼接后的字符串为101001
现在有q次修改,输入x,每次修改都会在使s[x]反转,即0->1,1->0,在后改后需要输出最少需要多少次交换(对s上的元素进行交换)可以使拼接后的字符串的字典序最大
题解
首先考虑到数据范围(n,m,q均为2e5),我们不可能真的去构建拼接后的字符串,所以考虑优化,只记录第一次出现的字符,
如样例中101001,实际上存储为1001,记为f,设1的个数为cnt1,对于f来讲,把前cnt1个元素全部置为1就是字典序最大的情况,所以只需要统计前cnt1个元素中有多少个0即可(此处还需考虑实际构建数组长度)
code
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define ll long long
#define NO cout<<"NO"<<endl
#define YES cout<<"YES"<<endl
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int mod = 1e9 + 7;
const int N = 2e6 + 10;
ll inf = (1ll << 60);
//priority_queue <int,vector<int>,less<int> > p;
//priority_queue <int,vector<int>,greater<int> > q;
struct BIT
{
int s[N];
int lowbit(int x)
{
return x & -x;
}
void update(int x, int y)
{
while (x < N)
{
s[x] += y;
x += lowbit(x);
}
}
int query(int x)
{
int res = 0;
while (x)
{
res += s[x];
x -= lowbit(x);
}
return res;
}
} tr;
int l[N], r[N];
int id[N];
int tot = 0;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T = 1;
// cin >> T;
while (T--)
{
int n, m, q;
string s;
cin >> n >> m >> q >> s;
s = ' ' + s;
rep(i, 1, m) cin >> l[i] >> r[i];
set<int>num;
rep(i, 1, n) num.insert(i);
rep(i, 1, m)
{
auto it = num.lower_bound(l[i]);
while (it != num.end() && (*it) <= r[i] )
{
int x = *it;
it++;
num.erase(x);
id[x] = ++tot;
}
}
int limit = tot;
int cnt1 = 0;
for (auto x : num) id[x] = ++tot;
rep(i, 1, n)
{
if (s[i] == '1') cnt1++;
else
{
tr.update(id[i], 1);
}
}
while (q--)
{
int x;
cin >> x;
if (s[x] == '1')
{
cnt1--;
tr.update(id[x], 1);
int sum = min(cnt1, limit);
cout << tr.query(sum) << endl;
s[x] = '0';
}
else
{
cnt1++;
tr.update(id[x], -1);
int sum = min(cnt1, limit);
cout << tr.query(sum) << endl;
s[x] = '1';
}
}
}
}