Codeforces Round #713 (Div. 3)
比赛链接
Codeforces Round #713 (Div. 3)
C. A-B Palindrome
一句话题意,给出 \(T\) 个由 0
、 1
、 ?
组成的字符串,以及这个字符串由 \(a\) 个 0
和 \(b\) 个 1
组成,要求将字符串中的 ?
替换成 0
或 1
之后是一个回文串并且恰好有 \(a\) 个 0
和 \(b\) 个 1
。
解题思路
模拟
想复杂了,之前想的是将奇数的情况转换为偶数的情况,然后只用判断偶数的情况。其实完全模拟一遍即可:从左到右对应位置上如果对称的两个字符出现矛盾,则不满足要求,否则按个数填入0
或1
,有0
填0
否则填1
,最后判断合法性即可
- 时间复杂度:\(O(n)\)
代码
// Problem: C. A-B Palindrome
// Contest: Codeforces - Codeforces Round #713 (Div. 3)
// URL: https://codeforces.com/contest/1512/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
int main()
{
int t,a,b;
for(cin>>t;t;t--)
{
cin>>a>>b;
string s;
cin>>s;
int n=s.size();
bool f=false;
int ta=0,tb=0;
for(int i=0,j=s.size()-1;i<j;i++,j--)
if(s[i]=='?'&&s[j]!='?')
{
s[i]=s[j];
if(s[i]=='0')ta+=2;
else
tb+=2;
}
else if(s[i]!='?'&&s[j]=='?')
{
s[j]=s[i];
if(s[i]=='0')ta+=2;
else
tb+=2;
}
else if(s[i]!='?'&&s[j]!='?')
{
if(s[i]!=s[j])
{
f=true;
break;
}
else
{
if(s[i]=='0')ta+=2;
else
tb+=2;
}
}
if(f)
{
puts("-1");
continue;
}
else
{
if(n&1)
{
if(s[n/2]=='0')ta++;
else if(s[n/2]=='1')tb++;
}
if(ta>a||tb>b)puts("-1");
else
{
a-=ta,b-=tb;
for(int i=0,j=s.size()-1;i<j;i++,j--)
if(s[i]=='?')
{
if(a>=2)s[i]=s[j]='0',a-=2;
else if(b>=2)s[i]=s[j]='1',b-=2;
else
{
f=true;
break;
}
}
if(f)puts("-1");
else
{
if(n%2==1&&s[n/2]=='?')
{
if(a)s[n/2]='0',a--;
else if(b)s[n/2]='1',b--;
}
if(a!=0||b!=0)f=true;
for(int i=0;i<n;i++)
if(s[i]=='?')f=true;
if(f)puts("-1");
else
cout<<s<<'\n';
}
}
}
}
return 0;
}
E. Permutation by Sum
一句话题意: \(T\) 组数据,每组数据由互相独立的 \(n, l, r, s\) 组成,求 \(\{a\} ,\{a\}\) 是 1 到 \(n\) 的一个排列使得 \(\sum_{i=l}^{r} a_{i}=s\) ,并输出这个排列,如果无法找到这样的排列输出 \(-1\) 。
解题思路
贪心,构造
对于一段连续的区间 \([l,r]\),选取 \(x\) 个数使其和为 \(s\),如果 \(s\) 在前 \(x\) 和后 \(x\) 个数之和之间,则一定可以找到一组方案满足要求
证明:类比于有 \(x\) 个点,从最小的 \(x\) 个点开始往上爬,每次最高的点开始慢慢向上爬,然后次高的点……每次权值和都只增加 \(1\),最后全部爬到最大的 \(x\) 个点上,故之间的所有 \(x\) 个数组成的和都可以取到,得证。
所以本题可以从 \(1\) 到 \(n\) 开始一个数一个数判断是否可以凑出给定的和
- 时间复杂度:\(O(n)\)
代码
// Problem: E. Permutation by Sum
// Contest: Codeforces - Codeforces Round #713 (Div. 3)
// URL: https://codeforces.com/contest/1512/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
int t,n;
int l,r,s,a[505];
int main()
{
for(cin>>t;t;t--)
{
cin>>n>>l>>r>>s;
vector<int> res;
int m=r-l+1;
for(int i=1;i<=n;i++)
if(s>0&&m>0&&(i+1)*(m-1)+(m-1)*(m-2)/2<=s-i&&s-i<=n*(m-1)-(m-1)*(m-2)/2)res.pb(i),s-=i,m--;
if(res.size()!=r-l+1)puts("-1");
else
{
unordered_set<int> s;
for(int i=l,j=0;i<=r;i++)s.insert(res[j]),a[i]=res[j++];
int t=1;
for(int i=1;i<l;i++)
{
while(s.count(t))t++;
a[i]=t++;
}
for(int i=r+1;i<=n;i++)
{
while(s.count(t))t++;
a[i]=t++;
}
for(int i=1;i<=n;i++)cout<<a[i]<<' ';
puts("");
}
}
return 0;
}