补题--6 (#598 Div.3)
网址: https://vjudge.net/contest/381168
codeforce的网址: https://codeforces.com/contest/1256
A(#598 Div.3 F)
题意:
给定两个字符串s和t,长度为n,你可以对一个字符串其中长度为l的一段进行翻转,l取值为1…n,但同时也必须对另一个串选择长度为l的一段进行翻转,这两个翻转的起点终点可以不一样。问你是否有可能在经过若干次操作后使得两个串变得相同。可能输出YES,否则输出NO。
官方代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef _DEBUG
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int q;
cin >> q;
for (int i = 0; i < q; ++i) {
int n;
string s, t;
cin >> n >> s >> t;
vector<int> cnts(26), cntt(26);
for (int j = 0; j < n; ++j) {
++cnts[s[j] - 'a'];
++cntt[t[j] - 'a'];
}
bool ok = true;
bool good = false;
for (int j = 0; j < 26; ++j) {
ok &= cnts[j] == cntt[j];
good |= cnts[j] > 1;
}
if (!ok) {
cout << "NO" << endl;
continue;
}
if (good) {
cout << "YES" << endl;
continue;
}
int invs = 0, invt = 0;
for (int l = 0; l < n; ++l) {
for (int r = 0; r < l; ++r) {
invs += s[l] > s[r];
invt += t[l] > t[r];
}
}
ok &= (invs & 1) == (invt & 1);
if (ok) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
B(#598 Div.3 D)
题意:
就是给定长度n的序列,由0,1构成,可以改变k次,改为最小序列。
思路:
首先找到零的位置,然后将零的位置尽量往前面移动
官方代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef _DEBUG
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int q;
cin >> q;
while (q--) {
int n;
long long k;
string s;
cin >> n >> k >> s;
string res;
int cnt = 0;
bool printed = false;
for (int i = 0; i < n; ++i) {
if (s[i] == '0') {
if (cnt <= k) {
res += '0';
k -= cnt;
} else {
res += string(cnt - k, '1');
res += '0';
res += string(k, '1');
res += s.substr(i + 1);//就是从i+1的这个位置开始到字符串结束。
cout << res << endl;//如果是substr(3,5),则是从3开始到5结束;
printed = true;
break;
}
} else {
++cnt;
}
}
if (!printed) {
res += string(cnt, '1');
cout << res << endl;
}
}
return 0;
}
C(#598 Div.3 A)
题意:
有a个价值是n的硬币,和b个价值是1的硬币,可以凑成s吗 ?可以yes,不可以no。
思路:
因为b的价值是1,所以就看s的价值减去a个n的价值比n大吗?
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int q,a,b,n,s;
cin>>q;
while(q--)
{
cin>>a>>b>>n>>s;
s-=min(s/n,a)*n;
if(s>b) cout << "NO" << endl;
else cout << "YES" << endl;
}
return 0;
}
D(#598 Div.3 E)
题意:
让我们根据所有学生的编程技能对他们进行排序,但是保存最初的索引来恢复答案。
现在我们可以理解,我们不需要组成一个规模大于5因为在这种情况下,我们可以把它分成更多的团队,更少的参与者,并获得相同的甚至更少的答案。
现在我们可以进行标准的动态规划了。dpi-如果我们将第一个部门划分为最低限度的总多样性i学生(按顺序排列)。一开始,dp0=0的所有其他值dp是+∞。由于上述事实,我们只能进行三次转换(0-索引):
dpi+3=min(dpi+3,dpi+ai+2−ai);
dpi+4=min(dpi+4,dpi+ai+3−ai);
dpi+5=min(dpi+5,dpi+ai+4−ai).
答案是dpn并且我们可以通过标准的带父值(作为我们可以使用的状态的父级,例如,团队中的参与者数)来恢复它。
官方代码:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pt;
#define x first
#define y second
#define mp make_pair
const int N = 200043;
const int INF = int(1e9) + 43;
int n;
int dp[N];
int p[N];
pt a[N];
int t[N];
int main() {
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
a[i].y = i;
scanf("%d", &a[i].x);
}
sort(a, a + n);
for(int i = 1; i <= n; i++)
{
dp[i] = INF;
p[i] = -1;
}
for(int i = 0; i < n; i++)
for(int j = 3; j <= 5 && i + j <= n; j++)
{
int diff = a[i + j - 1].x - a[i].x;
if(dp[i + j] > dp[i] + diff)
{
p[i + j] = i;
dp[i + j] = dp[i] + diff;
}
}
int cur = n;
int cnt = 0;
while(cur != 0)
{
for(int i = cur - 1; i >= p[cur]; i--)
t[a[i].y] = cnt;
cnt++;
cur = p[cur];
}
printf("%d %d\n", dp[n], cnt);
for(int i = 0; i < n; i++)
{
if(i) printf(" ");
printf("%d", t[i] + 1);
}
puts("");
return 0;
}
E(#598 Div.3 C)
题意:
一个人过河,然后给你这条河的长度,以及有几部分的慢板,还有他最远可以跳多远,以及这几块木板的大小,问你是否可以跳过,跳过最好的方法是什么
思路:
首先要判断的应该是我们是否可以跳过去,然而跳过去首先d跳的是否远,和几块木板有很重要的关系,首先我感觉我们可以倒着走,认为他可以走完,然后进行木板的放置,尽量是d的大小步伐,然后看到最后是否还可以到起点,可以则是yes同时也找到了最好的方法。
大佬代码:
和我的思路相反,他的想法是尽可能的扩大主人公所能到达的,即最远距离,如果最远距离都不符合要求,那么肯定就无法到达,如果最远距离超过了目的地,就将踏板尽可能的往前移。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<queue>
#include<map>
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x<b;x++)
#define W(x) printf("%d\n",x)
#define WW(x) printf("%lld\n",x)
#define pi 3.14159265358979323846
#define mem(a,x) memset(a,x,sizeof a)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int maxn=2e6+7;
const int INF=1e9;
const ll INFF=1e18;
int a[maxn],ans[maxn];
int main()
{
int n,m,d,now=0;
scanf("%d%d%d",&n,&m,&d);
rep(i,1,m)scanf("%d",&a[i]);
rep(i,1,m)
{
for (int j=d;j<=a[i]+d-1;j++)
ans[now+j]=i;//将每一块踏板都标上记号方便输出
now+=a[i]+d-1;
}
//now记录的是主人公能运动的最远距离
if (now+d<n+1)//无法到达的情况
{
cout<<"NO"<<endl;
}
else if (now>n)//超出目的地的情况,利用vector将踏板往前移
{
int res=now-n;
vector<int> V;
rep(i,1,now)
{
if (ans[i]==0&&res)res--;
else V.pb(ans[i]);
}
cout<<"YES"<<endl;
rep(i,0,n-1)cout<<V[i]<<" ";cout<<endl;
}
else//其余情况直接输出
{
cout<<"YES"<<endl;
rep(i,1,n)cout<<ans[i]<<" ";cout<<endl;
}
}
官方代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef _DEBUG
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int n, m, d;
cin >> n >> m >> d;
vector<int> c(m);
for (int i = 0; i < m; ++i) {
cin >> c[i];
}
vector<int> ans(n + 2);
for (int i = m - 1, pos = n; i >= 0; --i) {
for (int len = 0; len < c[i]; ++len) {
ans[pos - len] = i + 1;
}
pos -= c[i];
}
int now = 0;
while (true) {
while (now + 1 < n + 1 && ans[now + 1] > 0) ++now;
if (now + d >= n + 1) break;
if (ans[now + d] == 0) {
int lpos = -1;
for (int i = now + d; i < n + 2; ++i) {
if (ans[i] != 0) {
lpos = i;
break;
}
}
if (lpos == -1) {
cout << "NO" << endl;
return 0;
}
int rpos = -1;
for (int i = lpos; i < n + 2; ++i) {
if (ans[i] == ans[lpos]) rpos = i;
}
while (ans[now + d] == 0) {
swap(ans[lpos - 1], ans[rpos]);
--lpos, --rpos;
}
}
now += d;
}
cout << "YES" << endl;
for (int i = 1; i <= n; ++i) {
cout << ans[i] << " ";
}
cout << endl;
return 0;
}
F(#598 Div.3 B)
题意:
一个长度为n的序列然后对他进行n-1次的交换,然后构成置换是一个由n不同整数1到n按任意顺序排列。i 和i+1. 每个操作最多可以执行一次。
思路:
我的思路:
就是将最小的搞到最左,我的方法就是一一进行我的方法就是进行一一的比较,然后将最小的和它右边的大的相互交换。
官方思路:
和我的差不多,就是他运用了vector更加的方便简单相比较我的代码
我的这里有还vector的总结
官方代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef _DEBUG
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int q;
cin >> q;
for (int i = 0; i < q; ++i) {
int n;
cin >> n;
vector<int> a(n);
for (int j = 0; j < n; ++j) {
cin >> a[j];
--a[j];
}
int pos = 0;
while (pos < n) {
int nxt = min_element(a.begin() + pos, a.end()) - a.begin();
int el = a[nxt];
a.erase(a.begin() + nxt);
a.insert(a.begin() + pos, el);
if (pos == nxt) pos = nxt + 1;
else pos = nxt;
}
for (auto it : a) cout << it + 1 << " ";
cout << endl;
}
return 0;
}
我的代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=105;
int num[N];
int vis[N];
void init()
{
memset(vis,0,sizeof(vis));
vis[0]=1;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
}
int cnt=0;
int minn=1;
while(cnt<n-1&&minn!=n+1)
{
int p=1;
for(int i=1;i<=n;i++)
{
if(num[i]==minn)
{
p=i;
break;
}
}
while(vis[p-1]==0&&num[p-1]>num[p])
{
swap(num[p],num[p-1]);
vis[p-1]=1;
cnt++;
p--;
}
minn++;
}
for(int i=1;i<=n;i++)
{
printf("%d ",num[i]);
}
printf("\n");
}
return 0;
}