慢慢来。
题目 | A | B | C | D |
---|---|---|---|---|
tag | math | strings | greedy | dp |
状态 | √ | √ | √ | √ |
//∅,√,× |
想法
A. CME
res tp A
题意:有(n)根火柴,额外填上(k(k≥0))根火柴棍,使得(n+k)能分成三份(a,b,c),每份至少有一根火柴,满足(a+b = c),问(k)最小是多少
满足方程
(a+b+c = n+k)
(a + b = c)
得(2*c = n+k)
若(n)是偶数,那么(k)为零,反之(k)为(1)
特别地,(n)至少要为(4),才能凑出一个等式(1+1=2)
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i = (a);i>=(b);--i)
#define fo(i,a,b) for(int i =(a);i<(b);++i)
#define de(x) cout<<#x<<" = "<<x<<endl;
#define endl '
'
#define mem(a,b) memset(a,b,sizeof(a));
#define ls(p) ((p)<<1)
#define rs(p) (((p)<<1)|1)
using namespace std;
typedef long long ll;
const int mn = 105;
int n,q;
int main(){
cin>>q;
while(q--){
cin>>n;
if(n < 4)
cout<<4 - n<<endl;
else
cout<< (n&1) <<endl;
}
}
B. Strings Equalization
res tp B
题意:给出两个仅包含小写字母的字符串,问是否存在某个字符在两串中都出现过
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i = (a);i>=(b);--i)
#define fo(i,a,b) for(int i =(a);i<(b);++i)
#define de(x) cout<<#x<<" = "<<x<<endl;
#define endl '
'
#define mem(a,b) memset(a,b,sizeof(a));
#define ls(p) ((p)<<1)
#define rs(p) (((p)<<1)|1)
using namespace std;
typedef long long ll;
const int mn = 105;
char s[mn],t[mn];
int q,m;
bool vis[27],ans;
int main(){
cin>>q;
while(q--){
cin>>s>>t;
ans = 0;
mem(vis,0);
m =strlen(s);
rep(i,0,m-1) vis[ s[i]-'a' ] = 1;
rep(i,0,m-1) if(vis[t[i]-'a']){
ans = 1;break;
}
if(ans) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
C. Save the Nature
res tp C
题意:给定一个整数序列(p_i,iin[1,n]),你可以对其进行打乱顺序重新排列。定义了一个规则,下标是(a)的倍数的,可以有(x%)的贡献,下标是(b)的倍数的,可以有(y%)的贡献,问,在重排之后,按上述规则,从(1)开始,最少需要多少个连续的数,使得总贡献不小于(k)?
贪心地考虑,下标若既是(a)的倍数,又是(b)的倍数,那岂不是能贡献两份吗?我们先按从大到小的顺序钦定这类下标的元素值,之后再依照(x)与(y)的大小关系继续钦定剩下的对答案有贡献的位置,遍历区间([1,i]),执行上述操作,直到遇到第一个总贡献不小于(k)的下标,而那就是我们想要得到的最终答案。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i = (a);i>=(b);--i)
#define fo(i,a,b) for(int i =(a);i<(b);++i)
#define de(x) cout<<#x<<" = "<<x<<endl;
#define endl '
'
#define ls(p) ((p)<<1)
#define rs(p) (((p)<<1)|1)
using namespace std;
typedef long long ll;
const int mn = 2e5+10;
int n, q, na, nb, nc, x, y, a, b;
ll p[mn], k;
bool cmp1(ll a,ll b){return a>b;}
int ans;
inline ll gcd(ll x,ll y){
return (y == 0? x:gcd(y,x%y));
}
inline ll solve(int num){
na = num/a;nb = num/b;
nc = na&&nb?num/(a/gcd(a,b)*b):0; nb-=nc;na-=nc;
ll res = 0;
res += (p[nc] - p[0])*(x+y);
if(x > y){
res += (p[nc + na]- p[nc])*x;
res += (p[nc + na + nb] - p[nc + na])*y;
}
else{
res += (p[nc + nb] - p[nc])*y;
res += (p[nc + na + nb] - p[nc + nb])*x;
}
return res/100;
}
int main(){
scanf("%d",&q);
while(q--){
scanf("%d",&n);
rep(i,1,n) cin>>p[i];
sort(p+1,p+1+n,cmp1);
rep(i,1,n) p[i] += p[i-1];
scanf("%d%d%d%d",&x,&a,&y,&b);
scanf("%lld",&k);
ans = -1;
rep(i,1,n) if( solve(i) >=k ){
ans = i;
break;
}
printf("%d
",ans);
}
}
D. Sequence Sorting
res tp D
题意:给定一个序列,可以进行进行一种操作:选定一个x,之后将值为x的所有数字移动到序列的最左端或最右端,问最少进行多少次操作,使得序列满足单调不减
首先取出原序列中我们需要的信息,而其他的信息可以忽略。求出其每种元素的两个特征:初次出现位置和末次出现位置。
按元素值从小到大的序列就是我们最终要得到的序列。为了让操作数尽可能小,我们需要省去一些力气。如果原序列和终序列在某些地方是“相似”的,岂不是可以省去对这部分“相似”的操作吗?
具体地说,对终序列的两个数值紧邻的元素,若他们的分布区间不相交,且保证较小的元素的区间在较大的元素的左侧,那么这两种元素的相对位置在两个序列中是相等的,也就是说,它们对操作数没有贡献。
反之,至少要对其中的一个元素进行操作,同时,这也意味着,被操作元素那一侧的所有元素都要被操作。
综上,不需要操作的元素一定在终序列中是连续,于是可以dp出终序列满足条件的最长子区间,再用元素种类数减之即为答案
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i = (a);i>=(b);--i)
#define fo(i,a,b) for(int i =(a);i<(b);++i)
#define de(x) cout<<#x<<" = "<<x<<endl;
#define endl '
'
#define mem(a,b) memset(a,b,sizeof(a));
#define ls(p) ((p)<<1)
#define rs(p) (((p)<<1)|1)
using namespace std;
typedef long long ll;
const int mn = 3e5+10;
int q,n;
struct E{
int v,l,r;
}e[mn];
int vis[mn],t,cnt,mdp,dp;
bool cmp(E a,E b){return a.v <b.v;}
int main(){
scanf("%d",&q);
while(q--){
cnt = 1;
scanf("%d",&n);
rep(i,1,n){
scanf("%d",&t);
if(vis[t])
e[vis[t]].r = i;
else{
e[cnt].l = e[cnt].r = i;
e[cnt].v = t;
vis[t] = cnt++;
}
}
sort(e+1,e+cnt,cmp);
mdp = dp = 1;
int cnt1 = cnt - 1;
rep(i,2,cnt1){
if(e[i-1].r <e[i].l) ++dp;
else dp = 1;
mdp = max(mdp,dp);
}
printf("%d
",cnt - 1 - mdp);
rep(i,1,cnt1) vis[e[i].v] = 0;
}
}