传送门
题目大意:
已知按列排序的某个位置的数
求按行排序的相同位置的数
思路:
先计算给出的那个数按列排序的位置,然后在转化为按行排序的相同位置的数。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
void slove()
{
LL n,m,x;
cin >> n >> m >> x;
if(n == 1 || m == 1) {
cout << x << endl;
return ;
}
LL l = x%n;
if(l == 0) l = n;
LL k = x/n;
if(l != 0 && l != n) k++;
cout << (l-1)*m+k << endl;
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
slove();
}
return 0;
}
题目大意:
将首尾的*转化为X,要求每两个X之间的距离小于K,求将星号转化为X的最小次数。
思路:
从前往后遍历一遍指针推动X的位置即可
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
void slove()
{
int n,k;
cin >> n >> k;
string s;
cin >> s;
int cnt = 0,fre = 0,la = fre;
for(int i = 0;i < s.length();++i){
if(s[i] == '*' && cnt == 0){
fre = i;cnt = 1;
}
else if(s[i] == '*'){
if(i-fre > k){
fre = la;
cnt++;
}
la = i;
}
else if(s[i] == 'x') fre = i;
}
if(la != 0) cnt++;
cout << cnt << endl;
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
slove();
}
return 0;
}
传送门
题目大意:
寻找最大公共子串
思路:
dp
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
int dp[30][30];
int getLCS(string s, string t)
{
int result = 0;
int sLength = s.length();
int tLength = t.length();
for (int i = 0; i < sLength; i++) {
for (int k = 0; k < tLength; k++) {
if (s[i] == t[k]) {
if (i == 0 || k == 0) {
dp[i][k] = 1;
} else {
dp[i][k] = dp[i - 1][k - 1] + 1;
}
result = max(dp[i][k], result);
} else {
dp[i][k] = 0;
}
}
}
return result;
}
void slove()
{
string s,t;
cin >> s >> t;
cout << s.length()+t.length()-2*getLCS(s,t) << endl;
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
slove();
}
return 0;
}
传送门
题目大意:
两个不相同的数会相互抵消,求最后最少剩下几个数
思路:
求个数最多的数字的个数
如果个数大于一半2*ma - n
否则单数剩一个,双数剩0个
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
map<int,int> mp;
void slove()
{
int n;
cin >> n;
mp.clear();
int ma = 0;
for(int i = 1,x;i <= n;++i){
cin >> x;
mp[x]++;
ma = max(ma,mp[x]);
}
if(ma*2 <= n)
{
if(n%2 == 0) cout << 0 << endl;
else cout << 1 << endl;
}
else cout << n-2*(n-ma) << endl;
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
slove();
}
return 0;
}
传送门
题目大意:
给出一个序列第i个位置上的数字代表着原序列1~i的最大数
求原序列的最大序和最小序列
思路:
用数组来保存可能输出的数,序列中数字第一次出现就输出,
第二次出现就判断从前往后和从后往前输出确定序列
也可以使用二分,反向插数牛啊牛啊
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
set<int> s,s1;
int a[200020];
bool vis[200020];
vector<int> v;
void slove()
{
int n;
cin >> n;
s.clear();
s1.clear();
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
for(int i = 1;i <= n;++i){
cin >> a[i];
s.insert(-i);
s1.insert(i);
}
for(int i = 1;i <= n;++i){
s.erase(-1*a[i]);
s1.erase(a[i]);
}
for(int i = 1;i <= n;++i){
if(!vis[a[i]]){
cout << a[i] << " ";
vis[a[i]] = 1;
}
else {
cout << *s1.begin() << " ";
s1.erase(*s1.begin());
}
}
cout << endl;
memset(vis,0,sizeof(vis));
for(int i = 1;i <= n;++i){
if(!vis[a[i]]){
cout << a[i] << " ";
vis[a[i]] = 1;
}
else {
cout << -1**s.upper_bound(-a[i]) << " ";
s.erase(*s.upper_bound(-a[i]));
}
}
cout << endl;
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
slove();
}
return 0;
}
传送门
原题大意:
杨辉三角采用二维标记。
奇数向左走偶数向右走
求将所给数字联通的最小修改步数
思路:
将数字排序。
相邻两个数字如果同差,同为奇数差则不变,否则加上行差
如果不同差,则将上一个根据相对关系,将上一个转化成1,1
再求转换次数
#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(0),cin.tie(0)
#define rep(i,a,b) for(int i = a;i <= n;++i)
const int maxn = 1e5+5;
int r[maxn*2],l[maxn*2];
bool isLeftArrow(int r,int c)
{
return (r+c)%2 == 0;
}
bool isRightArrow(int r,int c)
{
return (r+c)%2 == 1;
}
int calcDist(int r1,int c1,int r2,int c2)
{
if(r1-c1 == r2-c2){
return isRightArrow(r1,c1)?0:r2-r1;
}
r2 -= r1-1;
c2 -= c1-1;
if(isLeftArrow(r1,c1)){
return (r2-c2)/2;
}
else return (r2-c2+1)/2;
}
void slove()
{
int n;
cin >> n;
for(int i = 1;i <= n;++i) cin >> r[i];
for(int i = 1;i <= n;++i) cin >> l[i];
vector<pair<int,int>> pts;
for(int i = 1;i <= n;++i) pts.emplace_back(r[i],l[i]);
sort(pts.begin(),pts.end());
int curC = 1,curR = 1;
int res = 0;
for(vector<pair<int,int>>::iterator it = pts.begin();it != pts.end();it++)
{
res += calcDist(curR,curC,it->first,it->second);
curR = it->first;
curC = it->second;
}
cout << res << endl;
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
slove();
cout << endl;
}
return 0;
}
传送门
题目大意:
每一个字母都unique的情况下,求最大的序列
思路:
单调栈,入栈弹栈操作。
保证每一个字符都cnt=1
#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(0),cin.tie(0)
int cnt[30];
bool vis[30];
stack<char> st;
vector<char> v;
void slove()
{
memset(cnt,0,sizeof(cnt));
memset(vis,false,sizeof(vis));
string s;
cin >> s;
int len = s.length();
v.clear();
for(int i = 0;i < len;++i) cnt[s[i]-'a']++;
for(int i = 0;i < len;++i){
while(!st.empty()){
if(vis[s[i]-'a']) {
cnt[s[i]-'a']--;
break;
}
if(st.top() > s[i]){
st.push(s[i]);
vis[s[i]-'a'] = true;
break;
}
else if(cnt[st.top()-'a'] > 1){
vis[st.top()-'a'] = false;
cnt[st.top()-'a']--;
st.pop();
}
else {
st.push(s[i]);
vis[s[i]-'a'] = true;
break;
}
}
if(st.empty()) {
st.push(s[i]);
vis[s[i]-'a'] = true;
}
}
while(!st.empty()){
v.push_back(st.top());
st.pop();
}
for(int i = v.size()-1;i >= 0;--i) cout << v[i];
return ;
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
slove();
cout << endl;
}
return 0;
}
总结:
这场div3的难度整体不高,主要在思路理解上和一些简单算法
主要学习到了单调栈,和反向插数的思想
以及最大公共子串的dp思想