Codeforces Round #690 (Div. 3)(A~F)
A题
简单模拟,按照题目写
#include<iostream>
using namespace std;
int n,t,a[500];
int main()
{
cin>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1,j=n;i<j;i++,j--)
cout<<a[i]<<' '<<a[j]<<' ';
if(n%2==1)cout<<a[n/2+1];
cout<<endl;
}
}
B题
给定一个字符串,可以进行一次操作,删除一个子串,使得剩下的为2020
因为只能删除一次,所以只会保留前i个字符和后4-i个字符 i取0 1 2 3 4 除此之外都不成立 所以直接判断前i个字符和后4-i个字符即可
#include<iostream>
using namespace std;
int t;
string s;
int main()
{
cin>>t;
while(t--)
{
int n,f=0;
cin>>n>>s;
for(int i=0;i<=4;i++)
{
string s2;
for(int k=0;k<i;k++)s2.push_back(s[k]);
for(int k=n-(4-i),add=1;add<=4-i;add++,k++)s2.push_back(s[k]);
if(s2=="2020")f=1;
}
if(f)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
C题
给定一个数x,找出最小的数使得各位数字之和为x,切各位数字不相同
这个数字最多只有9位,1到9的和为45,所以x>45则输出-1 否则应该选更大的数,因为会使位数尽量短,也就是数会越小
#include<iostream>
using namespace std;
int n,t;
int main()
{
cin>>t;
while(t--)
{
int st[10]={0};
cin>>n;
if(n>45)cout<<-1<<endl;
else
{
while(n)
{
for(int i=9;i>=1;i--)
{
if(i<=n)
{
st[i]=1;
n-=i;
}
}
}
for(int i=1;i<=9;i++)
if(st[i])cout<<i;
cout<<endl;
}
}
}
D题
有一个数组,每次可以将相邻的两个数合并,也就是将其划分成若干个部分,每部分的和都相同,一个部分内有x个数就进行了x-1次合并,求最小合并次数
第一个数属于的部分有n种情况,1~1 1~2 1~3 … 1~n,下面考虑后面的数能否组成第一个部分的和即可 复杂度 n^2
#include<iostream>
using namespace std;
long long a[100010],sum[3010],t,n;
int main()
{
cin>>t;
while(t--)
{
cin>>n;
sum[0]=0;
for(int i=1;i<=n;i++)cin>>a[i],sum[i]=sum[i-1]+a[i];
long long ans=n;
for(int i=1;i<=n;i++)
{
long long f=0,x=sum[i],now=0,add=0;
for(int i=1;i<=n;i++)
{
if(now+a[i]<x)now+=a[i],add++;
else if(now+a[i]==x)now=0;
else
{
f=1;
break;
}
}
if(f==0&&now==0)ans=min(ans,add);
}
cout<<ans<<endl;
}
}
E1&E2
E1和E2 做法相同,e1是e2的简单版,实际上难度差不多,直接给出e2的做法
题意:给定一个数组,选择m个数 这m个数的最大值和最小值的差要求小于等于k,问一共有多少组选法
先将数组排序,对于选择了ai的数 可以二分找ai+k的下标j 选择了ai的所有选法就是 在i+1到j中选择m-1个 很明显考虑的是选择了ai的情况,所以考虑完1到n即没有重复也没有遗漏 对于每种情况组合数即可
E1
#include<iostream>
#include<algorithm>
using namespace std;
long long a[200010],sum[3010];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n);
long long ans=0;
for(int i=1;i<=n;i++)
{
int r=upper_bound(a+1,a+1+n,a[i]+2)-a;
r--;
long long l=r-i;
if(a[r]-a[i]<=2&&l>=2)
ans+=l*(l-1)/2;
}
cout<<ans<<endl;
}
}
E2
#include<iostream>
#include<algorithm>
using namespace std;
long long a[200010],n,m,k;
const long long mod=1e9+7;
long long j[200010],nj[200010];
long long pows(long long a,long long b)
{
long long ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans%mod;
}
long long c(long long a,long long b)
{
return j[a]*nj[b]%mod*nj[a-b]%mod;
}
int main()
{
j[0]=nj[0]=1;
for(int i=1;i<=200000;i++)j[i]=j[i-1]*i%mod;
for(int i=1;i<=200000;i++)nj[i]=nj[i-1]*pows(i,mod-2)%mod;
int t;
cin>>t;
while(t--)
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n);
long long ans=0;
for(int i=1;i<=n;i++)
{
int r=upper_bound(a+1,a+1+n,a[i]+k)-a;
r--;
long long l=r-i;
if(a[r]-a[i]<=k&&l>=m-1)
ans=(ans+c(l,m-1))%mod;
}
cout<<ans<<endl;
}
}
F题
题意:有n个区间,删除x个区间,满足只要有一个区间和其他区间至少有一个交点,求x的最小值
先按照左端点排序
对于每一个区间 后面有多少区间与它有交点可以二分,前面有多少个区间与它有交点,可以差分,每次二分后,设为j说明i与(i+1,j)有交点,i+1,j进行加以差分即可
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
struct node
{
int x,y;
}a[200010];
int n;
int cha[200010],sum[200010];
bool cmp(node a,node b)
{
if(a.x==b.x)return a.y<b.y;
return a.x<b.x;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i].x,&a[i].y);
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{
int l=i+1,r=n;
while(l<r)
{
int mid=l+r+1>>1;
if(a[mid].x<=a[i].y)l=mid;
else r=mid-1;
}// i+1,r
if(a[l].x<=a[i].y)
{
cha[i+1]++;
cha[r+1]--;
sum[i]=r-i;
}
}
int ans=0;
for(int i=1;i<=n;i++)cha[i]+=cha[i-1];
for(int i=1;i<=n;i++)
ans=max(ans,cha[i]+sum[i]);
printf("%d\n",n-ans-1);
for(int i=1;i<=n+1;i++)
sum[i]=0,cha[i]=0;
}
}