A. Mainak and Array
第一种是不动第一个,那自然是2-n的最大值减第一个
第二种是不动最后一个,那自然是n减1-n-1的最小值
第三种是都动,那自然是相邻的差值
取所有可能的最大值即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
const int maxn = 2e6+10;
const int mod = 1e9+7;
int num[maxn];
void solve(){
int n;
cin>>n;
for(int i = 1;i<=n;i++){
cin>>num[i];
}
int cnt = 0;
for(int i = 1;i<=n;i++){
if(i==n)
cnt = max(cnt,num[n]-num[1]);
else
cnt = max(cnt,num[i]-num[i+1]);
}
for(int i = 1;i<n;i++){
cnt = max(cnt,num[n]-num[i]);
}
for(int i = 2;i<=n;i++){
cnt = max(cnt,num[i]-num[1]);
}
cout<<cnt<<endl;
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t = 1;
cin>>t;
while(t--){
solve();
}
}
B. Mainak and Interesting Sequence‘
构造题。
我们可以针对n是奇数或者偶数情况进行构造
n如果是奇数其实是最好构造的,n-1部分赋值成1,然后n是剩下的部分
n如果是偶数要分两种情况,一种是m是奇数的情况,这种是NO,m是偶数就可以构造n-2个1,然后剩下的平分即可。
假设排序好后为a1....a1(共num个) ,a2。对a2而言,a1一定要是具备偶数个的,否则对a2而言p值就不会为0了。而偶数个a1贡献出的sum也是偶数,到最后m无法平分,因此是不行的。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
const int maxn = 2e6+10;
const int mod = 1e9+7;
int num[maxn];
void solve(){
int n,m;
cin>>n>>m;
if(n>m){
cout<<"NO"<<endl;
return;
}
if(m%2==1&&n%2==0){
cout<<"NO"<<endl;
return;
}
cout<<"YES"<<endl;
if(n%2==1){
for(int i = 1;i<n;i++)
cout<<1<<" ";
cout<<m-n+1<<endl;
}
else{
for(int i =1;i<n-1;i++)
cout<<1<<" ";
cout<<(m-n+2)/2<<" "<<(m-n+2)/2<<endl;
}
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t = 1;
cin>>t;
while(t--){
solve();
}
}
C. Jatayu's Balanced Bracket Sequence
问有几个连通块,但是由于左括号和右括号是一定连通的,所以其实可以转化成左括号彼此之间是否连通的问题。
我们经过观察可以得知只有出现并列才会产生新的连通块
((()))像这样三个左括号并不会产生新的连通
但是如果是(()())这样 第二个左括号和第三个左括号会产生连通,即包含关系不会连通,而并列关系会连通。
在一个合法的括号序列中,并列关系的个数是夹杂在所有左括号中的右括号
或者是左右括号相邻 s[i]=='(’&&s[i+1] == ')' 的个数
算出来产生新联通的个数用n减去即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
const int maxn = 1e6+10;
const int mod = 1e9+7;
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t = 1;
cin>>t;
while(t--){
int n;
cin>>n;
string s;
cin>>s;
int ans = n;
int cnt = n;
int j = 0;
for(int i = 0;i<s.size();i++){
if(s[i]=='('){
j = 1;
cnt--;
if(!cnt)
break;
}
if(j&&s[i]==')'){
j = 0;
ans--;
}
}
cout<<ans<<endl;
}
}
D. Edge Split
完全没有思路的题=-=
感觉比较好的题解大概是这个意思。对于每一条边而言,在不考虑成环情况下,它能让连通块整数-1,但是如果成环了那么这条边就木大了。
分红蓝线又要让C1+C2最小,其实就是让红不成环,蓝也不成环。
同时要注意m<=n+2这一条件,我们可以考虑最小生成树的概念(已知整张图是连通的),我们可以确定n-1条边不成环并标上红色,那么最多剩下3条边,如果成环只有三元环的情况,我们将其中一条边v改成红色。
同时改了以后红色出现环,我们将v的一个端点的所有边改成蓝色就可以去掉环了。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
const int maxn = 1e6+10;
int a[maxn],b[maxn];
int f[maxn];
int find(int x){
if(f[x]==x)
return x;
return f[x] = find(f[x]);
}
int same(int x,int y){
if(find(x)==find(y)){
return 1;
}
return 0;
}
int merge(int x,int y){
if(same(x,y))
return 0;
f[find(x)] = find(y);
return 1;
}
pair<int,int>p[maxn];
void solve(){
int n,m;
cin>>n>>m;
for(int i = 1;i<=n;i++){
f[i] = i;
}
int s,e;
vector<vector<pair<int,int>>>v(n+1);
vector<int>ans(m+1);
for(int i = 1;i<=m;i++)
ans[i] = 1;
for(int i = 1;i<=m;i++){
cin>>s>>e;
p[i] = {s,e};
if(merge(s,e)){
v[s].push_back({e,i});
v[e].push_back({s,i});
}
else
ans[i] = 0; //不在最小生成树内
}
if(n+2==m){
set<int>ss;
int now = 0;
for(int i = 1;i<=m;i++){
if(!ans[i]){
ss.insert(p[i].first);
ss.insert(p[i].second);
now = i;
}
}
if(ss.size()==3){//说明是三元环
ans[now] = 1; //标红
int point = p[now].first; //一个端点
for(auto i:v[point]){
ans[i.second] = 0;
}
for(int i = 1;i<=m;i++){
cout<<ans[i];
}
cout<<endl;
}
else{
for(int i = 1;i<=m;i++){
cout<<ans[i];
}
cout<<endl;
}
}//可能三元环
else{
for(int i = 1;i<=m;i++){
cout<<ans[i];
}
cout<<endl;
}
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t = 1;
cin>>t;
while(t--){
solve();
}
}