解题顺序是A、D、B、C,B题代码改了一个多小时,找了半天判断条件,最后还是用了暴力swap,然后导致时间不太够了,B题只是看了看题意。
其他题目也基本都看了一遍,但是不怎么会做,需要提高的地方还是有很多。
A、Payment Without Change
【题意、思路、解题过程】
题意大体是给了a个价值为n的硬币,b个价值为硬币,问能不能拼出S。
水题,优先用价值为n的硬币,看剩下的s是否大于等于b即可。
【代码】
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
int main()
{
int t;
ll b,a,n,s;
cin >> t;
while(t--)
{
cin >> a >> b >> n >> s;
ll num = s/n;
if(num >a)
num = a;
s -= num*n;
if(b>=s)
cout << "YES"<<endl;
else
cout << "NO"<<endl;
}
return 0;
}
B、Minimize the Permutation
【题意、思路、解题过程】
题意大体是给你n个数的序列,最多进行n-1次操作,每次操作把a[n-1]与a[n]交换位置,但每个位置的操作至多只能使用一次,求字典序最小排列。
大体思路是贪心,因为n个数是[1,2,……,n]所以从1开始找,找到1,把1一路换到第一个位置,然后从1原来的位置开始找2,找到2换到这个位置,以此类推。
这道题wa了好多次,一直没想暴力交换怕超时,然后一直有个点怎么也写不对,最后发现n最大为100……然后暴力解决了。
【代码】
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
int a[101];
int main()
{
int t,n;
cin >> t;
while(t--){
cin >> n;
for(int i=1;i<=n;i++)
cin >> a[i];
int tt=1,lp=1;
while(tt<=n){
lp=tt;
for(int i=tt;i<=n;i++){
//找剩下的数字中最小的数
if(a[tt]>a[i]){
tt=i;
}
}
if(tt==lp){
tt++;continue;}
for(int i=tt-1;i>=lp;i--)
swap(a[i],a[i+1]);
}
for(int i=1;i<=n;i++)
cout << a[i] << " ";
cout <<endl;
}
return 0;
}
C、Platforms Jumping![在这里插入图片描述](https://img-blog.csdnimg.cn/20200709004001814.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1OTQ5OTE0,size_16,color_FFFFFF,t_70)
【题意、思路、解题过程】
题意大体是要你跨过一条河,长度位n,给你m个板子,每一个板子的长度告诉你,你可以跳d的距离,求如果要过河,板子的摆放情况。
首先可以考虑他每次可以越过d-1个水格子,那么他可以跳过的总的水沟格数最大应该是d-1 乘以木板的个数+1。这个加上木板长度的总和,可以判断是否可以安全跳到对岸。
接下来是输出答案的问题,首先考虑把所有木板全部挨着放在右边,然后左边按照最大d-1的距离隔开,先计算出需要用多少块木板隔开,然后输出这些木板以及水沟,最后的剩下的木板全挨着排在右边,依次输出他们的编号就行。
因为B题耗费了一个多小时,这道题只是看了看题目没解。
【代码】
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int MAXN = 1005;
int arr[MAXN],ans[MAXN];
int main()
{
int n,m,d;
int sum=0,pos=0;
cin >> n >> m >> d;
for(int i=1; i<=m; i++)
{
cin >> arr[i];
pos+=d+arr[i]-1;
sum+=arr[i];
}
if(pos+d<n+1)//人能到达的最远距离
{
cout << "NO" << endl;
return 0;
}
cout << "YES" << endl;
pos=0;
for(int i=1; i<=m; i++)
{
if(pos+d+sum-1<=n)
pos+=d;
else pos=n-sum+1;
for(int j=pos; j<=pos+arr[i]-1; j++)
ans[j]=i;
pos+=arr[i]-1;
sum-=arr[i];
}
for(int i=1; i<=n; i++)
cout << ans[i] << " ";
cout <<endl;
return 0;
}
D、Binary String Minimizing
【题意、思路、解题过程】
题意大体是给你个长度为n的01字符串,然后移动k次,让字典序尽量小。
还是贪心,找到0尽量往前拿即可。
这道题用队列写了下,刚开始想的是置换,找位置然后先输出0后把前面的1输出,但写出来很麻烦,后来就想到置换,然后用了队列记录每个0的位置,然后尽量往前置换就可以了。
【代码】
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
int a[1000010];
int main()
{
ll t;
string str;
ll n,k;
cin >> t;
while(t--)
{
queue<ll>q;
ll num=0;
cin >> n >> k >> str;
for(int i=0;i<n;i++)
if(str[i]=='0')
q.push(i);
while(!q.empty()&&k>0)
{
int tt = q.front();
q.pop();
if(tt-num<=k)
{
swap(str[num],str[tt]);
k -= (tt-num);
}else{
swap(str[tt],str[tt-k]);
k=0;
}
num++;
}
cout << str <<endl;
}
return 0;
}
E、Yet Another Division Into Teams
【题意、思路、解题过程】
题意大体是n个数分组每组的数的个数至少三个求如何分组才能使分组之后各组的极差之和最小。
思路,首先从大到小排序,这个时候有个贪心策略,每个组最多为连续的5个人。如果6个人,分成两组一定更优。然后就可以dp求解了。
这道题没想到怎么写,更没想到是用dp解决的。。。。
【代码】
#include<bits/stdc++.h>
#define LL long long
using namespace std;
#define inf 0x3f3f3f3f
struct node{
int i,x;
}a[200005];
LL f[200005];
int vis[200005];
int p[200005];
int cmp(node &a, node &b){
return a.x>b.x;
}
int main()
{
int n;
cin >> n;
for(int i=1; i<=n; i++){
f[i]=inf;
cin >> a[i].x;
a[i].i=i;
}
sort(a+1, a+n+1, cmp);
f[0]=0;
for(int i=3; i<=n; i++){
if(i-3+1>=1&&f[i]>f[i-3]+a[i-3+1].x-a[i].x){
f[i]=f[i-3]+a[i-3+1].x-a[i].x;
p[i]=i-3;
}
if(i-3>=1&&f[i]>f[i-3-1]+a[i-3].x-a[i].x){
f[i]=f[i-3-1]+a[i-3].x-a[i].x;
p[i]=i-3-1;
}
if(i-3-1>=1&&f[i]>f[i-3-2]+a[i-3-1].x-a[i].x){
f[i]=f[i-3-2]+a[i-3-1].x-a[i].x;
p[i]=i-3-2;
}
}
cout << f[n] << " ";
int L=p[n], R=n, tot=1;
while(R){
while(R>L){
vis[a[R].i]=tot;
R--;
}
R=L, L=p[R], tot++;
}
cout << tot-1 <<endl;
for(int i=1; i<=n; i++)
cout << vis[i] << " ";
cout <<endl;
return 0;
}
F、Equalizing Two Strings
【题意、思路、解题过程】
题意大体是给出两个长度相等的字符串,每次操作必须同时翻转两个字符串中相同长度的子串,求是否可以通过这种操作使得两个串相等
大体思路也是参考了其他人的博客,首先yes的条件要两个子串的组成字母不同类型的个数完全一样,否则no。完全一样后如果有某个字母出现超过两次,那么先把这两个相同的字母移到一起,然后只需要每次都选择长度为2的操作,并且其中一个串只选择翻转这两个相同的字母,那么就可以做到改变其中一个串并且保持另一个串不变,很容易可以得到答案。若没有两个相同的字母,那么一定是两两不同的,那么两个串的每个字母一定是一一对应的。那么固定一个串每次交换最后两位,让另一个串从第一位开始匹配,若匹配完前n-2项后后两项相同,那么yes,否则no。
这道题刚开始,连题意都没看明白,现在看起来是个思维题目
【代码】
#include<bits/stdc++.h>
#define LL long long
using namespace std;
#define inf 0x3f3f3f3f
int a[26],b[26];
int main()
{
int t,n;
cin >> t;
while(t--)
{
string s,t;
for(int i=0;i<26;i++)
b[i]=a[i]=0;
cin >> n >> s >> t;
for(int i=0;i<n;i++)
{
b[s[i]-'a']++;
a[t[i]-'a']++;
}
bool ok=true,ac=false;
for(int i=0;i<26;i++)
{
if(b[i]!=a[i]) ok=false;
if(b[i]>1) ac=true;
}
if(!ok)
{
cout << "NO" << endl;
continue;
}
if(ac)
{
cout << "YES" << endl;
continue;
}
int is=0,it=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<i;j++)
{
is+=s[i]>s[j];
it+=t[i]>t[j];
}
}
if((is&1)==(it&1))
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}