自闭的构造场。一周不练,该场VP回到解放前qwq。
C-Unequal Array(GOOD)
思路
- 最优解的性质:选取的区间一定连续。否则产生2个满足 e q u a t i l i t y equatility equatility条件的一对数
- 剔除与问题无关的区间。至少要消灭原数组多余的equatity对
- 方法是作用于第一个满足 a i = a i + 1 a_i = a_{i+1} ai=ai+1的i和最后一个满足 a j = a j + 1 a_j = a_{j+1} aj=aj+1的j组成的区间[i+1,j]。
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <map>
#include <queue>
#include <chrono>
#include <math.h>
#include <unordered_map>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int t;
cin >> t;
for(int i = 0;i<t;i++)
{
int n;
cin >> n;
int a[n];
for(int k = 0;k<n;k++) cin >> a[k];
int firstid = INT_MAX;
int lastid = -1;
for(int k = 0;k<n-1;k++)
{
if(a[k] == a[k + 1])
{
firstid = min(firstid,k);
lastid = max(lastid,k);
}
}
if(lastid == -1 || firstid == lastid) cout << 0 << endl;
else if(lastid == firstid + 1) cout << 1 << endl;
else cout << lastid - firstid - 1 << endl;
}
system("pause");
return 0;
}
D题-Cyclic Rotation
思路
- 考察由a生成b的过程,判断匹配:不断将a中与末尾相同的元素移动到末尾。故b中最后一块相等元素块从左往右第一个元素就能和a的最后一个元素匹配。对a的倒数第二个元素,同理。一直到最前(没有考虑倒数第二个及之前的qwq)
- 利用双指针。从后向前匹配b和a。b中多余的项目计入multiset中。
- 学习multiset的删除:利用迭代器删除,只删除一个。直接erase,全部删除。
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <map>
#include <queue>
#include <chrono>
#include <math.h>
#include <unordered_map>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int t;
cin >> t;
for(int i = 0;i<t;i++)
{
int n;
cin >> n;
int a[n],b[n];
for(int k = 0;k<n;k++) cin >> a[k];
for(int k = 0;k<n;k++) cin >> b[k];
multiset<int> s;
int p = n - 1,q = n - 1;
bool flag = true;
while(p >= 0 && q>=0)
{
int curb = b[p];
while(p - 1 >= 0 && b[p - 1] == curb)
{
s.insert(curb);
p--;
}
if(b[p] == a[q]) {p--;q--;}
else
{
multiset<int>::iterator iter = s.find(a[q]);
if(iter!=s.end())
{
q--;
s.erase(iter);
}
else
{
flag = false;
break;
}
}
}
if(!flag)
{
cout << "NO" << endl;
}
else
{
while(q >=0)
{
multiset<int>::iterator iter = s.find(a[q]);
if(iter!=s.end())
{
s.erase(iter);
}
else
{
flag = false;
break;
}
q--;
}
if(!flag) cout << "NO" << endl;
else cout << "YES" << endl;
}
}
system("pause");
return 0;
}
E-notepad.exe(交互题)-搜索空间的减少很GOOD![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ed7d9f73881abbf6fa6832e859172fd7.png)
思路
- n种可能的高度。1-n。
- 如果在每种高度搜索最小width query数量不可接受。
- 特殊条件入手:每个单词都摆在一行,之间仅有一个空格。且最后无尾随空格。可以采用二分查找搜索出这个最小width,设为S。
- 关键一步:对给定的高度H,下界是
S
−
(
H
−
1
)
S - (H - 1)
S−(H−1)(空格最多减少H-1个,且每行无尾随空格)(减小搜索空间).因此对每个高度,最优解的搜索空间为
[
S
−
H
+
1
,
S
]
[S-H + 1,S]
[S−H+1,S].
- 最优解取值必须是H的倍数。而在[S-H+1,S]中仅有 ⌊ S / H ⌋ ⋅ H \lfloor S/H \rfloor \cdot H ⌊S/H⌋⋅H满足条件。
- 因此对每个高度H,查询 w i d t h = ⌊ S / H ⌋ width = \lfloor S/H \rfloor width=⌊S/H⌋,如果查询结果等于H,则更新答案。
- 总结:本题关键在于求出当H=1,摆放所有单词需要的最小width;其他高度的搜索空间不能超过这个最小width。以及这些其他高度最多能使得这个最小width还能减少的面积(每一行末尾至多能少一个空格)。从而减少对于每个高度的搜索空间。
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <map>
#include <queue>
#include <chrono>
#include <math.h>
#include <unordered_map>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int n;
cin >> n;
int l =1,r = n * 2000 + 1 + n;
while(l < r)
{
int m = (l + r) >> 1;
cout << "?" << " " << m << endl;
cout.flush();
int h_w; cin >> h_w;
if(h_w != 1) l = m + 1;
else r = m;
}
int a = l;
for(int H = 2;H<=n;H++) //对每个高度搜索最优解
{
cout << "?" << " " << l/H << endl;
cout.flush();
int h_w; cin >> h_w;
if(h_w == H) a = min(a,h_w * (l / H));
}
cout << "!" << " " << a << endl;
system("pause");
return 0;
}
F1题- Array Shuffling(GOOD)-复习置换的知识(very good)![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a92a95c504c10128b8bf070dcc523f53.png)
思路(使用Graph表示)
- a中每个数字表示一个结点,若i位置需要交换到j位置,则从i对应的结点到j对应的结点连一条边
- 则图是不相交的环构成的集合。设环的数量为 k k k个,每个环表示k-1次交换.因此总共n-k次交换
- 交换次数上界:保证每个环上不存在相同的元素,否则可以拆成两个环.设数组中出现最多的数的次数为cnt,则sadness最大只可能取到n-cnt
- 存在使得sadness为n-cnt的构造算法.只需设置n-cnt个组别,然后依次加入数据即可.
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <map>
#include <queue>
#include <chrono>
#include <math.h>
#include <unordered_map>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<int> cnt[200001];
int main()
{
int t;
cin >> t;
for(int i = 0;i<t;i++)
{
int n;
cin >> n;
int max = -1;
int maxnum = -1;
int d[n];
set<int> c;
for(int k = 0;k<n;k++) {
int a;cin >> a;cnt[a].push_back(k);d[k]=a;
if((int)cnt[a].size() > max)
{max = cnt[a].size();maxnum = a;}
c.insert(a);
}
vector<int> group[max];
int cur = 0;
for(int k : c)
{
while(cnt[k].size() > 0)
{
group[cur].push_back(cnt[k][cnt[k].size() - 1]);
cnt[k].pop_back();
cur = (cur + 1) % max;
}
}
//交换数组d
for(int k = 0;k<max;k++)
{
for(int q = 0;q<group[k].size() - 1;q++)
{
swap(d[group[k][q]],d[group[k][q+1]]);
}
}
for(int k = 0;k<n-1;k++) cout << d[k] << " ";
cout << d[n-1]<<endl;
}
system("pause");
return 0;
}
F2-Checker for Array Shuffling
V
e
r
y
G
O
O
D
Very \ GOOD
Very GOOD![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/19fd37b1225b213bee98d57e912da1f3.png)
思路
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <map>
#include <queue>
#include <chrono>
#include <math.h>
#include <unordered_map>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<int> cnt[200001];
bool dfs(bool vis[],int n,bool instack[],int cur)
{
instack[cur] = true;
vis[cur] = true;
for(int u : cnt[cur])
{
if(instack[u] == true) return true;
if(vis[u] == true) continue;
if(dfs(vis,n,instack,u) == true) return true;
}
instack[cur] = false;
return false;
}
void solve()
{
int n;
cin >> n;
int a[n];
for(int i = 0;i<n;i++) cin >> a[i];
int max_num = 0;
int max_cnt = -1;
for(int i = 0;i<n;i++)
{ int b;
cin >> b;
cnt[a[i]].push_back(b);
if((int)cnt[a[i]].size() > max_cnt) {max_num = a[i];max_cnt = cnt[a[i]].size();} //统计出现次数最多的数字
}
bool vis[n+1];
bool instack[n+1];
memset(vis,0,(n+1)*sizeof(bool));
memset(instack,0,(n+1)*sizeof(bool));
//运行dfs判断是否有回路
vis[max_num] = true;
bool flag = true;
for(int v:a)
{
if(!vis[v])
{
if(dfs(vis,n,instack,v))
{
flag = false;
break;
}
}
}
if(flag) cout << "AC" << endl;else cout<<"WA"<<endl;
for(int v : a) cnt[v].clear();
}
int main()
{
int t;
cin >> t;
while(t--) solve();
system("pause");
return 0;
}
H题-Zigu Zagu
思路(直观)
- A:对0,1对删除。(0,1段相接)
- B:然后在每段单独删除多余的0,1(直到每段留下1个)
- A + B = max( ∑ ( 连 续 0 段 中 0 的 个 数 − 1 ) , ∑ ( 连 续 1 段 中 1 的 个 数 − 1 ) \sum (连续0段中0的个数 - 1),\sum (连续1段中1的个数- 1) ∑(连续0段中0的个数−1),∑(连续1段中1的个数−1)),求和为对所有的连续0段,1段求和。
- 最后构成一个尽可能长的0-1交替串,删除这个交替串。
- 最终操作数:A+B-1
- 方法:利用前缀和统计;
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <map>
#include <queue>
#include <chrono>
#include <math.h>
#include <unordered_map>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int n,q;
cin >> n >> q;
string a;
cin >> a; //长度为n的string字符串
int pre0[n];
int pre1[n];
bool mark[n];
memset(mark,1,n*sizeof(bool));
int k = 0;
while(k < n)
{
mark[k] = false;
char cur = a[k];
int pre0_ = k == 0?0:pre0[k-1];
int pre1_ = k == 0?0:pre1[k-1];
pre0[k] = pre0_;
pre1[k] = pre1_;
k++;
while(k<n && a[k] == cur)
{
if(cur=='0') {pre0[k] = pre0[k-1] + 1;pre1[k] = pre1[k-1];}
else {pre1[k]=pre1[k-1]+1;pre0[k] = pre0[k-1];}
k++;
}
}
for(int i = 0;i<q;i++)
{
int l,r;
scanf("%d %d",&l,&r);
l--;r--;
int d;
if(l-1<=0) d= 0; else d = pre0[l-1];
int num_0 = pre0[r] - d;
if(l-1 <=0) d=0; else d = pre1[l-1];
int num_1 = pre1[r] - d;
if(mark[l] && a[l] == '0') num_0--;
if(mark[l] && a[l] == '1') num_1--;
printf("%d\n",max(num_0,num_1) + 1);
}
system("pause");
return 0;
}