A.Circle of Students
题意:给你1个1到n的排列,看能不能顺时针或者逆时针围城一个圈
做法可以向前向后判断,或者看一个两倍数组,检测有没有顺序或者逆序排列
B.Equal Rectangles
题意: 给你一堆火柴,问你能不能围成n个大小相等的矩形
思路: 排序后把最大和最小长度的火柴组一起就行,要注意判断给的火柴数目是不是偶数
C.Common Divisors
题意:给你n个数,要你求这n个数的公因数的个数
思路:求出这n个数的最大公约数,然后算这个数的因子个数,就是这n个数的公因数个数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=4e5+5;
ll a[MAX];
ll GCD(ll a, ll b){
if(b==0){
return a;
}
return GCD(b,a%b);
}
ll countt(ll n){
ll s=1;
for(ll i=2;i*i<=n;i++){
if(n%i==0){
ll a=0;
while(n%i==0){
n/=i;
a++;
}
s=s*(a+1);
}
}
if(n>1) s=s*2;
return s;
}
int main (){
int n;
cin>>n;
ll gcd=0;
for(int i=0;i<n;i++){
scanf("%lld",&a[i]);
if(i>0)
gcd=GCD(a[i],gcd);
else
gcd=a[i];
}
cout<<countt(gcd)<<endl;
return 0;
}
D1 D2 . Remove the Substring
题意: 给你两个字符串s1,s2 问你从s1中能删去的最长字串长度,删去后使得s2仍然是s1的子序列
思路:能删去的最长长度分为3中情况,一种是s2第一个字符在s1序列中最后出现的位置,或者最后一个字符在s1序列中第一次出现的位置,或者同一种字符在中间的最大间隔
#include <bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
int a[MAX],b[MAX];
int main(){
string s1,s2;
cin>>s1>>s2;
int len1=s1.length(),len2=s2.length();
int j=0;
for(int i=0;i<len2;i++){
while(s1[j]!=s2[i]) j++;
a[i]=j; //左边遍历找到最先出现的位置
j++;
}
j=len1-1;
for(int i=len2-1;i>=0;i--){
while(s1[j]!=s2[i]) j--;
b[i]=j; //右边遍历找到最后出现的位置
j--;
}
int ans= max (ans , max (len1-1-a[len2-1],b[0])); // 找到左边空间或者右边空间最大的那一个
for(int i=0;i<len2;i++){
ans= max (ans,(b[i+1]-a[i]-1)); //把第一个出现的和最后一个出现的后面那一个找到
// 减1是因为最后一个不能删
}
cout<<ans<<endl;
return 0;
}
E.Boxers
题意:给你n个数,每个数只能加1或者减1,问你改变后最多有多少个不相等的数
思路:从大到小排序,然后用一个数组来维护一个数是否出现过,首先看这个数+1是否出现过,否则不变,如果不变的话也出现过就令他减1,最后再遍历一遍看有多少个数被数组标记过
#include <bits/stdc++.h>
using namespace std;
bool cmp(const int a,const int b){
return a>b;
}
const int MAX=150000+5;
int a[MAX],ex[MAX];
int main (){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
sort(a,a+n,cmp);
a[0]++;
ex[a[0]]=1;
for(int i=1;i<n;i++){
if(ex[a[i]+1]!=1){
a[i]++;
}
else {
if(ex[a[i]]==1){
if(ex[a[i]-1]==0&&a[i]>1){
a[i]--;
}
}
}
ex[a[i]]=1;
}
int ans=0;
for(int i=0;i<MAX;i++){
if(ex[i]==1){
ans++;
}
}
cout<<ans<<endl;
return 0;
}
F1.Complete the Projects (easy version)
题意:给定n个项目,和一个初始权值r。每个项目有两个数值构成,rating表示要进行这个项目的最低权值需求,get表示进行完这个项目后权值将会变化的数值。询问能否完成所有的项目。
思路:贪心。分开保存get为正和负的项目,正的按rating从小到大排序后直接取。负的需要按rating+get排序。详细证明与说明可以看这篇博客https://www.cnblogs.com/st1vdy/p/11352620.html
#include <bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
struct node {
int rating;
int get;
}a[MAX],t1[MAX],t2[MAX];
bool cmp(const struct node a ,const struct node b){
return a.rating<b.rating;
}
bool cmpp(const struct node a,const struct node b){
return a.rating+a.get>b.rating+b.get;
}
int main (){
int n,r;
cin>>n>>r;
int k=0,kk=0;
for(int i=0;i<n;i++){
cin>>a[i].rating>>a[i].get;
if(a[i].get>=0) t1[k++]=a[i];
else t2[kk++]=a[i];
}
sort(t1,t1+k,cmp);
sort(t2,t2+kk,cmpp);
int flag=0;
for(int i=0;i<k;i++){
if(r<t1[i].rating){
flag=1;
break;
}
else r+=t1[i].get;
}
if(flag){
cout<<"NO"<<endl; return 0;
}
for(int i=0;i<kk;i++){
if(r<t2[i].rating){
flag=1;
break;
}else {
r+=t2[i].get;
}
if(r<0){
flag=1;
break;
}
}
if(flag){
cout<<"NO"<<endl;
}
else
cout<<"YES"<<endl;
return 0;
}
F2.Complete the Projects (hard version)
与F1 不同的地方在于,我们需要尽量多地完成项目,在取正数部分和F1做法一样,在负数部分,我们既要尽可能的完成,又要尽量的使权值r尽量减得更少,就变成了一个dp
#include <bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
struct node {
int rating;
int get;
}a[MAX],t1[MAX],t2[MAX];
int dp[MAX];
bool cmp(const struct node a ,const struct node b){
return a.rating<b.rating;
}
bool cmpp(const struct node a,const struct node b){
return a.rating+a.get<b.rating+b.get;
}
int main (){
int n,r;
cin>>n>>r;
int k=0,kk=0;
for(int i=0;i<n;i++){
cin>>a[i].rating>>a[i].get;
if(a[i].get>=0) t1[k++]=a[i];
else t2[kk++]=a[i];
}
sort(t1,t1+k,cmp);
sort(t2,t2+kk,cmpp);
int flag=0;
int ans=0;
for(int i=0;i<k;i++){
if(r<t1[i].rating){
flag=1;
break;
}
else {
r+=t1[i].get;
ans++;
}
}
for(int i=0;i<kk;i++){
for(int j=r;j>=abs(t2[i].get)&&j>=t2[i].rating;j--){
dp[j]=max(dp[j],dp[j+t2[i].get]+1);
}
}
cout<<ans+dp[r]<<endl;
return 0;
}
dp[j]表示权值剩余j的时候完成的项目个数,所以它等于不完成当前项目或者完成当前项目权值减少get ,项目数+1 的最大值。