【解题报告】CF DIV3 #ROUND 713 A~E
比赛链接
这次比较稳,3题一发A掉,但是A题没有速A,8000人才通过,排名3900+,分数回涨还行
可能被hack的人比较多吧,结束的时候排5200,出来居然只有3900+
A. Spy Detected!
思路
开局以为只要输出是哪个数,后来发现要输出下标啊啊啊,时间拖延了好多
暴力模拟一遍就完事了
代码
// Problem: A. Spy Detected!
// Contest: Codeforces - Codeforces Round #713 (Div. 3)
// URL: https://codeforces.com/contest/1512/problem/A
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// FishingRod
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
/*DATA & KEY
*/
int T;
const int N=105;
int a[N];
void solve(int T)
{
//NEW DATA CLEAN
map<int,int>mp;
//NOTE!!!
int n;cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
mp[a[i]]++;
}
int k;
for(auto t:mp)
if(t.second==1)
{
k=t.first;
break;
}
for(int i=1;i<=n;i++)
if(k==a[i])
{
cout<<i<<endl;
break;
}
}
int main()
{
scanf("%d",&T);
while(T--)solve(T);
return 0;
}
B. Almost Rectangle
思路
还是模拟,只要形成矩形即可,比较特殊的情况是行或者列相同。需要特殊处理一下。
任意答案所以如果同行或者同列那就尝试两个方向移动一格即可
题解采用了取模的方法来防止出界,也是挺不错的
代码
// Problem: B. Almost Rectangle
// Contest: Codeforces - Codeforces Round #713 (Div. 3)
// URL: https://codeforces.com/contest/1512/problem/B
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// FishingRod
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
/*DATA & KEY
*/
int T;
const int N=405;
char g[N][N];
void solve(int T)
{
//NEW DATA CLEAN
memset(g,0,sizeof g);
//NOTE!!!
int n;cin>>n;
for(int i=0;i<n;i++)cin>>g[i];
int x1,y1,x2,y2;
bool flag=1;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(g[i][j]=='*')
{
if(flag)
{
x1=i,y1=j,flag=0;
}
else x2=i,y2=j;
}
g[x1][y2]=g[x2][y1]='*';
if(x1==x2)
{
if(x1+1<n)g[x1+1][y1]=g[x1+1][y2]='*';
else g[x1-1][y1]=g[x2-1][y2]='*';
}
if(y1==y2)
{
if(y1+1<n)g[x1][y1+1]=g[x2][y2+1]='*';
else g[x1][y1-1]=g[x2][y2-1]='*';
}
for(int i=0;i<n;i++)cout<<g[i]<<endl;
}
int main()
{
scanf("%d",&T);
while(T--)solve(T);
return 0;
}
C. A-B Palindrome
思路
还是模拟,比赛时写的代码比较冗余吧。
大致的思路如下
预处理部分
①把已知的或者可以推测出来的用标记一波(st数组)
②然后再遍历一遍,把可以推测出的问号确定下来,同时判断有没有产生冲突。确定后其实就变成a和b确定,然后给你一个由问号构成的串,看能不能用a个1和b个0构成回文串
构造部分
③统计已经确定的0和1的数量,然后判a和b是否足够,并通过奇偶判能否构成回文串
④有点贪心的操作,0和1哪个多用哪个
代码
// 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
// FishingRod
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
/*DATA & KEY
*/
int T;
const int N=4E5+10;
int st[N];
void solve(int T)
{
//NEW DATA CLEAN
memset(st,-1,sizeof st);
//NOTE!!!
int a,b;cin>>a>>b;
string s;cin>>s;
for(int i=0;s[i];i++)
{
if(s[i]=='0')st[a+b-i-1]=0,st[i]=0;
else if(s[i]=='1')st[a+b-i-1]=1,st[i]=1;
}
bool flag=1;
for(int i=0;s[i];i++)
{
if(s[i]=='?'&&st[i]!=-1)s[i]=('0'+st[i]);
else if(s[i]=='1'&&st[i]==0)
{
puts("-1");flag=0;break;
}
else if(s[i]=='0'&&st[i]==1)
{
puts("-1");flag=0;break;
}
}
int cnt=0;
int ta=a,tb=b;
if(flag)
{
for(int i=0;s[i];i++)
{
if(s[i]=='0')ta--;
if(s[i]=='1')tb--;
if(s[i]=='?')cnt++;
}
if(ta<0||tb<0||ta+tb!=cnt||(ta%2==1&&tb%2==1))
{
puts("-1");flag=0;
}
if(flag)
{
for(int i=0;s[i];i++)
{
if(s[i]=='?')
{
if(ta>tb)//用0
{
s[i]='0';ta--;
if(a+b-1-i!=i)s[a+b-1-i]='0',ta--;
}
else
{
s[i]='1';tb--;
if(a+b-1-i!=i)s[a+b-1-i]='1',tb--;
}
}
}
cout<<s<<endl;
}
}
}
//1?1 012 2
int main()
{
scanf("%d",&T);
while(T--)solve(T);
return 0;
}
D. Corrupted Array
思路
这题比赛的时候没啥思路,看了题解后意识到题目读错了
区分
b
n
+
1
=
a
1
+
a
2
+
…
…
+
a
n
b_{n+1}=a_1+a_2+……+a_n
bn+1=a1+a2+……+an和
b
i
+
1
=
a
1
+
a
2
+
…
…
+
a
i
b_{i+1}=a_1+a_2+……+a_i
bi+1=a1+a2+……+ai啊,小憨憨!
重新梳理一下题意吧!对5个要求逐个分析翻译
给你一个n,和n+2个数,
- 然后选两个数(⑤,因为是shuffled所以相当于选数了),
- 一个作为x(④)
- 一个作为数组a的和(③)
- 其他的作为a的元素(②)
- 问你能不能构造出a(①)
b
n
+
1
=
S
u
m
a
b_{n+1}=Sum_a
bn+1=Suma
S
u
m
b
=
2
∗
S
u
m
a
+
x
Sum_b=2*Sum_a+x
Sumb=2∗Suma+x
x
=
S
u
m
b
−
2
∗
S
u
m
a
x=Sum_b-2*Sum_a
x=Sumb−2∗Suma
显然的,
b
n
+
1
b_{n+1}
bn+1一定是排列后最大的两个中的一个
从小到大排序后
如果
S
u
m
a
=
b
n
+
1
Sum_a=b_{n+1}
Suma=bn+1,那么
x
=
b
n
+
2
x=b_{n+2}
x=bn+2
如果
S
u
m
a
=
b
n
+
2
Sum_a=b_{n+2}
Suma=bn+2,那么
x
=
S
u
m
b
−
2
∗
b
n
+
2
x=Sum_b-2*b_{n+2}
x=Sumb−2∗bn+2
代码
// Problem: D. Corrupted Array
// Contest: Codeforces - Codeforces Round #713 (Div. 3)
// URL: https://codeforces.com/contest/1512/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// FishingRod
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
/*DATA & KEY
*/
int T;
const int N=2E5+10;
int b[N];
void solve(int T)
{
//NEW DATA CLEAN
memset(b,0,sizeof b);
LL s=0;
//NOTE!!!
int n;cin>>n;
for(int i=1;i<=n+2;i++)
{
cin>>b[i];
s+=b[i];
}
sort(b+1,b+3+n);
LL x,sa;
//第一种
sa=b[n+1];x=b[n+2];
if(s-2*sa==x)
{
for(int i=1;i<=n;i++)cout<<b[i]<<" ";
cout<<endl;
return;
}
//第二种
sa=b[n+2];x=s-2*b[n+2];
int pos=lower_bound(b+1,b+n+2,x)-b;
if(pos<=n+1&&b[pos]==x)
{
for(int i=1;i<=n+1;i++)
if(i!=pos)cout<<b[i]<<" ";
cout<<endl;
return;
}
puts("-1");
}
int main()
{
scanf("%d",&T);
while(T--)solve(T);
return 0;
}
E. Permutation by Sum
思路
输出1~n的一种排列数,使得【L,R】区间和为s,如果不存在就输出-1.
比赛最后看了一眼,想到01背包,但是问题是,如果对L,R区间做背包,如何确定哪些物品作为可选物品?然后就结束了
正解:
首先判有没有可能:对于区间[L,R],s的值最小为1+2+3+……,最大为n+n-1+n-2+……
如果是在区间内那么从最小的1+2+3+……开始逐渐让这些数字变大直到为s
那么如何逐渐让这些数字变大呢
每次用可选的里第一个比a[R]大的数,替换掉a[R],如果没有的话就说明要替换a[R-1]了
然后疯狂写爆啊啊,参考了大佬的博客然后加了些注释
代码
// 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
// FishingRod
// 参考:https://blog.csdn.net/sjjzslhhh/article/details/115598278
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
/*DATA & KEY
*/
int T;
const int N=505;
int a[N];
bool st[N];
void solve(int T)
{
//NEW DATA CLEAN
memset(st,0,sizeof st);
//NOTE!!!
int n,l,r,s;cin>>n>>l>>r>>s;
int len=r-l+1;
LL low=len*(1+r-l+1)/2;
LL high=len*(n+n-len+1)/2;
if(s<low||s>high){puts("-1");return;}
int k=0,t=0,c=l-1;
k=(s-low)/len,t=(s-low)%len;//原本取模取错了
for(int i=len;i>=1;i--)
{
int d=i;
if(t)
{
d++;
t--;
}
d+=k;
a[++c]=d;
st[d]=1;
}
//处理[1~l-1]
int h=0;
for(int i=1;h<l-1;i++)
{
if(!st[i])
{
h++;
cout<<i<<" ";
st[i]=1;
}
}
for(int i=l;i<=r;i++)cout<<a[i]<<" ";
for(int i=1;i<=n;i++)
{
if(!st[i])
{
cout<<i<<" ";
st[i]=1;
}
}
cout<<endl;
}
int main()
{
scanf("%d",&T);
while(T--)solve(T);
return 0;
}
反思
A:
看清题目
B:
取模防止出界,输出任意那就搞个成功概率最大的,移动小一点
C:
先预处理以及标记看有没有冲突,对问题进行化简
D:
分清下标是定值还是变化的
shuffle:打乱的,往往意味着可以把问题转化为选数
E:
对于判断存在结果为某个值的方案,可以先看这个值可能的范围来判断是否存在方案。
一堆数,选n个数来让和为某个值,可以先选最小的,然后逐个增大(让每次变化最小)