CF #486 DIV3
A
题意:给数组a,从a中找出k个不一样的数。
思路:桶一下即可
#include<bits/stdc++.h>
using namespace std;
int vis[200];
vector<int>v;
int main(){
int n,k;scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
int sc;scanf("%d",&sc);
if(!vis[sc])
vis[sc]=1,v.push_back(i);
}
if(v.size()>=k){
puts("YES");for(int i=0;i<k;i++)printf("%d ",v[i]);
}
else puts("NO");
return 0;
}
B
题意:给n个字符串si,问reorder后是否可以保证每一个si是后si+1的子串。
思路:相同长度的字符串一定是相同的,否则长的包含短的,那么只需要排序后判断一下就行了。
#include<bits/stdc++.h>
using namespace std;
string a[105];
bool cmp(string x,string y){return x.length()<y.length();}
bool check(string x,string y){
int lx=x.length(),ly=y.length();
for(int i=0;i<ly;i++){
if(i+lx-1>=ly)continue;
int tag=1;
for(int j=0;j<lx;j++){
if(x[j]!=y[i+j]){tag=0;break;}
}
if(tag)return 1;
}
return 0;
}
int main(){
int n;cin>>n;for(int i=0;i<n;i++)cin>>a[i];sort(a,a+n,cmp);
int tag=1;
for(int i=0;i<=n-2;i++){
if(check(a[i],a[i+1])==0){tag=0;break;}
}
if(tag) {
puts("YES");
for(int i=0;i<n;i++) cout<<a[i]<<'\n';
}
else puts("NO");
return 0;
}
C
题意:给k个数组,挑出两个数组,使得这两个数组分别删去一个元素后和相同。
思路:枚举每一个可以得到的和,将可以得到和放入set,然后每次得到新的和,去set里找是否可以得到答案。时间复杂度O(nlogn)
#include<bits/stdc++.h>
using namespace std;
const int MX=2e5+5;
struct no{int h,l,s;};
bool operator<(const no &x,const no &y){
return x.s<y.s;
}
set<no>se;set<no>::iterator it;
int a[MX];
int q,w,e,r;
int main(){
int k;scanf("%d",&k);for(int j=1;j<=k;j++){
int n;scanf("%d",&n);int sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);sum+=a[i];
}
for(int i=1;i<=n;i++){
int now=sum-a[i];it=se.find(no{0,0,now});
if(it!=se.end()){
q=it->h,w=it->l,e=j,r=i;
}
}
for(int i=1;i<=n;i++)se.insert(no{j,i,sum-a[i]});
}
if(q)printf("YES\n%d %d\n%d %d",q,w,e,r);
else puts("NO");
return 0;
}
D
题意:给n个在x轴上的点,从中挑出尽量多的数,使得任意两两之间的距离是2的倍数。
思路:最多选三个数,且是等差数列,那么sort之后枚举那个差就行了。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int MX=2e5+5;
LL a[MX];
int main(){
int n;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
sort(a+1,a+1+n);
int ans=0,book[5];
for(LL i=1;i<=INT_MAX;i=i*2){
for(int j=1;j<=n;j++){
vector<int>v;v.clear();v.push_back(a[j]);
int id1=lower_bound(a+1,a+1+n,a[j]-i)-a;
if(id1!=n+1&&a[id1]==a[j]-i)v.push_back(a[id1]);
id1=lower_bound(a+1,a+1+n,a[j]+i)-a;
if(id1!=n+1&&a[id1]==a[j]+i)v.push_back(a[id1]);
if(v.size()>ans){
ans=v.size();
for(int i=0;i<v.size();i++) book[i]=v[i];
}
}
}
printf("%d\n",ans);
for(int i=0;i<ans;i++)printf("%d ",book[i]);
return 0;
}
E
题意:给一个整数n,相邻两位可以交换,但是交换过程中不能有前导零,求最小的交换次数使得n可以整除25.
思路:可以整除25的时候,最后两位是 {00,25,50,75},那么4种都去考虑一下是否可行,对于每一次考虑,先决定个位,再决定十位。注意前导零的处理。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int MX=2e5+5;
char zzz[4][2]={'2','5','5','0','7','5','0','0'};
int main(){
string n;cin>>n;int ln=n.length();
int ans=-1;
for(int i=0;i<4;i++){
int u[2]={-1,-1};string nn=n;
for(int j=0;j<2;j++){
for(int k=ln-1-j;k>=0;k--){
if(nn[k]==zzz[i][j^1]){
u[j]=k;
for(int z=k;z<ln-1-j;z++){
nn[z]=nn[z+1];
}
nn[ln-1-j]=zzz[i][j^1];
break;
}
}
}
if(u[0]!=-1&&u[1]!=-1){
int tt=ln-2-u[0]+ln-1-u[1];
if(nn[0]=='0'){//如果第一位被拿走了
int p;
for(p=0;p<ln;p++){
if(nn[p]!='0')break;
}
if(p<=ln-2) tt=tt+p;
else continue;
}
if(ans==-1)ans=tt;
else ans=min(ans,tt);
}
}
cout<<ans;
return 0;
}
F
题意:ly生活在一条直线上,ly在点0,要去点a,其中n个连续的区间在下雨,有m个点有雨伞,ly需要到有雨伞的地方拿伞,在下雨的区间需要有伞,伞有重量,求最小的ly的疲劳值(伞的重量*拿伞的路程) (其实有更简单的解法。。。
思路:定义dp[ly的位置][拿的伞的重量],发现肯定开不下,发现最多2000*2000个状态,就用map离散化dp。
一个点一个点的走,有雨没雨,有伞没伞分类讨论即可..
注意:1.可能一个点有多个伞!!!(wa了好几次 2.注意处理下雨的区间和拿伞的时间点,我定义是经过这个点后达到的状态
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int MX = 2005;
map<int,int>mp[2];bool rain[MX];int un[MX];
int main(){//规定走到[l,r)时有雨,伞在点上,经过这个点
int a,m,n;cin>>a>>n>>m;
while(n--){
int l,r;scanf("%d%d",&l,&r);
for(int i=l;i<r;i++)rain[i]=1;
}
for(int i=1;i<=m;i++){
int sc1,sc2;scanf("%d%d",&sc1,&sc2);
if(un[sc1])un[sc1]=min(sc2,un[sc1]);
else un[sc1]=sc2;
}
int now=0;mp[now][0]=0;
for(int i=0;i<=a;i++){
if(mp[now].size()==0){puts("-1");return 0;}
mp[now^1].clear();
int mi=INT_MAX; //找一个最小的值
for(auto it:mp[now]){//继承前面的状态
mi=min(mi,it.second);
if(it.first==0&&rain[i]){
continue;
}
mp[now^1][it.first]=it.second+it.first;
}
if(rain[i]==0) mp[now^1][0]=mi; //扔掉伞
if(un[i])mp[now^1][un[i]]=mi+un[i];//捡起伞
now=now^1;
}
int ans =INT_MAX;
for(auto it:mp[now]) ans=min(ans,it.second);
cout<<ans;
return 0;
}
别人的解法:
思路:考虑每一个下雨的区间,去寻找最佳的拿伞的地方。
dp[i]=dp[i-1](无雨) dp[i]=dp[j-1]+(i-j+1)*un[j] (有伞的地方转移过来) 注意i==0和j==0时候数组越界状态无法记录的情况。
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int MX = 2005;
int dp[MX];bool rain[MX];int un[MX];
int main(){//规定走到[l,r)时有雨,伞在点上,经过这个点
int a,m,n;cin>>a>>n>>m;
while(n--){
int l,r;scanf("%d%d",&l,&r);
for(int i=l;i<r;i++)rain[i]=1;
}
for(int i=1;i<=m;i++){
int sc1,sc2;scanf("%d%d",&sc1,&sc2);
if(un[sc1])un[sc1]=min(sc2,un[sc1]);
else un[sc1]=sc2;
}
for(int i=0;i<=a;i++){
dp[i]=INT_MAX/2;
if(!rain[i]){
dp[i]=((i==0)?0:dp[i-1]);
}
else{
for(int j=0;j<=i;j++){
if(un[j]){
dp[i]=min(dp[i],(j==0?0:dp[j-1])+(i-j+1)*un[j]);
}
}
if(dp[i]==INT_MAX/2){puts("-1");return 0;}
}
}
cout<<dp[a];
return 0;
}