【解题报告】CF DIV3 #ROUND 710 A~E
A.Strange Table
思路
一眼题,希望校园网给力些
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int T;
signed main()
{
cin>>T;
while(T--)
{
ll n,m,x;
cin>>n>>m>>x;
ll a=(x-1)%n,b=(x-1)/n+1;
cout<<a*m+b<<endl;
}
return 0;
}
B. Partial Replacement
题意:
距离限制,相邻x距离不能超过给定值k,而且第一个和最后一个‘*’必须改成‘x’。可以把‘*’改成‘x’,但是’.'不行。问最少改几个满足条件。
思路
又被B杀了
原本想的是尽可能要减少改的次数,那么让相邻x距离尽可能大然后我就直接每次跳k个距离看是不是‘*’是的话就改,不是的话就不管,然后最后检查以下最后一个有没有改掉,没有的话补一个。
这样就出现了一个问题,对于某一个与前一个‘x’距离小于k的‘*’如果你不改的话,可能以后就没有’*‘来改,这样可能导致和后面的x距离差距太大了。说的直白一些就是说了有这个限制,你要是一直贴着这个边干的话,未来可能稍有不顺,你就没了。
然后看了看官方题解,发现:不是“*”的话就不管,这么干是不对的,应该再往前找找有没有需要改变的。
所以正确的贪心描述是:在最多能跨k距离的情况下,寻找里左端点最远的’*'修改
代码
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
/*DATA & KEY
*/
int T;
void solve(int T)
{
//NEW DATA CLEAN
//NOTE!!!
int n,k,ans;
ans=1;
string s;
cin>>n>>k>>s;
int l=s.find_first_of('*');//第一次知道有这玩意
while (true)
{
int j = min(n - 1, l + k);
for (; l < j && s[j] == '.'; j--) {}//逆向找,来实现
if (l == j) {
break;
}
ans++;
l = j;//更新左端点
}
cout<<ans<<endl;
}
int main()
{
scanf("%d",&T);
while(T--)solve(T);
return 0;
}
C.Double-ended Strings
题意
给两个串,四个操作,可以选择把a或b首或者尾字母删掉,问最少操作多少次可以让a和b相等
思路
比较裸的求最长公共子串(不是子序列啊啊啊)
i
f
(
a
[
i
]
=
=
b
[
j
]
)
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
−
1
]
+
1
if(a[i]==b[j])dp[i][j]=dp[i-1][j-1]+1
if(a[i]==b[j])dp[i][j]=dp[i−1][j−1]+1其他的
d
p
[
i
]
[
j
=
0
dp[i][j=0
dp[i][j=0
不过数据量挺小的也可以拿BFS做
代码
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
const int N=25;
int T;
int f[N][N];
void solve()
{
int maxcom=0;
memset(f,0,sizeof f);
char a[N],b[N];
cin>>(a+1)>>(b+1);
int la=strlen(a+1),lb=strlen(b+1);
for(int i=1;i<=la;i++)
for(int j=1;j<=lb;j++)
{
if(a[i]==b[j])f[i][j]=f[i-1][j-1]+1;
else f[i][j]=0;
maxcom=max(maxcom,f[i][j]);
}
cout<<la+lb-2*maxcom<<endl;
}
int main()
{
scanf("%d",&T);
while(T--)solve();
return 0;
}
D.Epic Transformation
思路
又是分组配对问题,不同数字的可以组成一组,问最多可以组多少组,优先队列动态维护数量最多的那组和其他组一个个配对(不用太跳,一个个来挺不错的,先实现了再考虑优化)
代码
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
/*DATA & KEY
t 1e4
total n 2e5
ai 1e9
*/
const int N=2e5+10;
int T;
map<int,int>mp;
void solve(int T)
{
mp.clear();
int n;
cin>>n;
for(int i=0,x;i<n;i++)
{
cin>>x;
mp[x]++;
}
priority_queue<int>heap;
for(auto t:mp)heap.push(t.second);
while(heap.size()>1)
{
int t=heap.top();heap.pop();
int k=heap.top();heap.pop();
t--;k--;
if(t)heap.push(t);
if(k)heap.push(k);
}
if(heap.size())cout<<heap.top()<<endl;
else cout<<0<<endl;
}
int main()
{
scanf("%d",&T);
while(T--)solve(T);
return 0;
}
E.Restoring the Permutation
思路
字典序最小:直接暴力整一波就够了。主要是字典序最大,如果从后面找<x且没用过的数的话很容易TLE。
找小于x的最大可用的数可以想到使用二分来优化,借助set可以实现这一操作,而且set支持:插入,删除,查找。可以比较好的维护数是否可用,而且本身支持二分查找。
代码
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
/*DATA & KEY
t: 1 1e4
total n: 1 2e5
q: 1 n
*/
const int N=2e5+10;
int T;
int q[N];
bool st[N];
map<int,int>mp;
void solve(int T)
{
//NEW DATA CLEAN
memset(q,0,sizeof q);
memset(st,0,sizeof st);
mp.clear();
//NOTE!!!
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>q[i];
for(int i=1;i<=n;i++)mp[q[i]]++;
set<int>s;
for(int i=1;i<=n;i++)s.insert(-i);
int k=1;
for(auto t:mp)
{
int x=t.first,y=t.second;
printf("%d ",x);
st[x]=1;
for(int i=1;i<y;i++)
{
while(st[k])k++;
printf("%d ",k);
st[k]=1;
}
}
puts("");
for(auto t:mp)
{
int x=t.first,y=t.second;
printf("%d ",x);
s.erase(-x);
for(int i=1;i<y;i++)
{
auto it=s.upper_bound(-x);
int tmp=*it;
printf("%d ",-tmp);
s.erase(tmp);
}
}
puts("");
}
int main()
{
scanf("%d",&T);
while(T--)solve(T);
return 0;
}
反思
A:
无他,网快手快
B:
相邻元素最大距离有限制,问最少改几次,满足条件。
最少改几次转化为,每次改的相邻距离尽可能大。
string字符串查找第一个元素的用法
int i=s.find_first_of('*');
C:
两字符串经过系列操作变为相同串最小操作次数,联想到最短编辑距离和最长公共子序列
不过根据操作特点,这题要写最长公共子串而非最长公共子序列。
分清公共子串和公共子序列。
数据量小可以BFS乱搞
D:
多组配对问题,问最多配多少组。
统计每组数量,然后贪心让当前数量最多的和其他组配对
优先队列维护最多组数量。
一个个配对,数据量小不用跳着搞
E:
字典序贪心。
寻找小于x的最大值,联想到二分优化。
set支持排序,二分查找,插入,去重,删除。