补题--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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值