A.Creating the Contest
题意:给你一串递增的数字,要你从中选取子序列,满足子序列的每个元素都满足 a i + 1 ≤ a i ∗ 2 a_{i+1}\le a_i*2 ai+1≤ai∗2 ,问这个子序列的最大长度。
解题思路:明显可以看出,这个子序列肯定是连续的,举个例子,1 2 5 6,2 5 6从5开始就已经断开了,不可能再连上6,所以必须是连续的,那就相当于找最大的子串了,那么就直接枚举一遍,然后更新最大长度就行了。
AC代码:
#include <bits/stdc++.h>
using namespace std;
int a[200005];
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int n;cin>>n;
int sum = 1;
int ans = 1;
for(int i=0;i<n;++i)cin>>a[i];
for(int i=1;i<n;++i){
if(a[i]<=2*a[i-1])++sum;
else{
ans = max(ans,sum);
sum=1;
}
}
ans = max(ans,sum);
cout<<ans;
return 0;
}
B.LCM Challenge
题意:给你一个数 n n n,要你找三个小于等于 n n n的正数(可以相同),使得这三个数的最大公倍数最大。
解题方法:要使 l c m lcm lcm最大,不就相当于找一下小于等于n的互质的最大的3个数么。然后我们知道,两个连续的自然数必然是互质的,且两个连续的奇数也是互质的,那么n是奇数就输出 n ∗ ( n − 1 ) ∗ ( n − 2 ) n*(n-1)*(n-2) n∗(n−1)∗(n−2),如果是偶数,只需要讨论一下, n n n和 n − 3 n-3 n−3是否互质,然后再看 n − 1 n-1 n−1是奇数,按奇数的求法求个值,再求两者的最大值就行了。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
ll n;cin>>n;//一定要记得开long long
if(n==1)cout<<1;
else if(n==2)cout<<2;
else{
if(n&1)cout<<n*(n-1)*(n-2);
else{
ll ans=0;
if(gcd(n,n-3)==1)ans=n*(n-1)*(n-3);
ans = max(ans,(n-1)*(n-2)*(n-3));
cout<<ans;
}
}
return 0;
}
C.Many Equal Substrings
题意:给你一个字符串s,然后要你求一个新的字符串,能找到k个s,要使这个字符串的长度最小。
解题方法:这,一眼看,就是求s的最大前缀和后缀相等的长度,因为每次后缀都可以是下一个字符串的前缀。
AC代码:
#include <bits/stdc++.h>
using namespace std;
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int n,k;cin>>n>>k;
string s;cin>>s;
int ind = 0;
for(int i=0;i<n;++i){
if(s.substr(0,i)==s.substr(n-i))ind = i;
}
cout<<s;
string a = s.substr(ind);
for(int i=1;i<k;++i)cout<<a;
return 0;
}
D.How many ways
题意:一个机器人在走矩阵,只能向右或向下走,初始的时候有 ( 1 , 1 ) (1,1) (1,1)下标的所有能量,每走一格消耗一点能量,走到指定的位置,获得这个格子上的所有能量(之前的消失了),问有多少种方法走到 ( n , m ) (n,m) (n,m)的位置。
解题方案:dp,这种是一眼一看就要dp的题,如果做过直接计数从矩阵左上走到矩阵右下的题,就知道这题是增强版,多了可以去的地方的限制,用自底向上的方法好写。
#include <bits/stdc++.h>
using namespace std;
const int MOD=10000;
int a[105][105],dp[150][150];
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T;cin>>T;
while(T--){
memset(dp,0,sizeof(dp));//每次使用前把dp数组置0
int n,m;cin>>n>>m;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j)cin>>a[i][j];
}
dp[1][1] = 1;//初始状态
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
int r = a[i][j]+i;//机器人在这个格子的能量能到达的最大的行数
int c = a[i][j]+j;//机器人在这个格子的能量能到达的最大的列数
for(int q=i;q<=r;++q){
for(int w=j;w<=c;++w){
if(q==i&&w==j)continue;//原位
dp[q][w]+=dp[i][j];
dp[q][w]%=MOD;
}
--c;//每往下一行,机器人能到的列数就要-1
if(j>c)break;//如果列数已经到了原来列数左边,就要退出了
}
}
}
cout<<dp[n][m]<<'\n';
}
return 0;
}
E.最短路
题意:从商店起点,到赛场终点之间有很多条路,给定走这些路的时间,我们要选一条用时最短的路。
题解:典型的求最短路的题,我头铁了8发,发现忘了处理没边的路,不了解的可以去学学最短路,解决这方面的题往往用dijsktra,bellman_ford,floyd。
AC代码:
#include <bits/stdc++.h>
using namespace std;
int cost[150][150];
void floyd(int n){
for(int k=0;k<n;k++){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(cost[i][k] == -1 || cost[k][j] == -1)continue;
if(cost[i][j]==-1||cost[i][j]>cost[i][k]+cost[k][j]){
cost[i][j]=cost[i][k]+cost[k][j];
}
}
}
}
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int n,m;
while(cin>>n>>m){
if(!n&&!m)break;
memset(cost,-1,sizeof(cost));
for(int i=0;i<m;++i){
int u,v,c;
cin>>u>>v>>c;
--u,--v;
cost[u][v]=c;
cost[v][u]=c;
}
floyd(n);
cout<<cost[0][n-1]<<'\n';
}
return 0;
}
F.Heaters
题意:给一个长为 n n n的只含0,1的数组,0表示没有暖气开关,1表示有暖气开关,暖气的最大范围为 r r r,即假设暖气的位置为 p o s pos pos,数组 [ p o s − r + 1 , p o s + r − 1 ] [pos-r+1,pos+r-1] [pos−r+1,pos+r−1]的位置都被暖气充盈,问是否能使暖气充满整个数组,若不能输出-1,能输出最少要开几个。
解题方案:CF的经验告诉我,这么长的题目,不是难题就是简单题,贪,往死里贪,就每次看看要开哪个,尽量往右取,能覆盖前面的开关能达到的最大范围的打开就行了,贪就完事。
AC代码:
#include <bits/stdc++.h>
using namespace std;
int a[1005];
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int n,r;cin>>n>>r;
for(int i=0;i<n;i++)cin>>a[i];
int ans = 0;
int t = 0;//记录被覆盖的区间的最右的位置
while(t<n){
int pos=-1;
for(int i=0;i<n;++i){
if(a[i]){
if(i-r+1<=t&&i+r-1>=t)//看能不能覆盖前面的区间,能就更新。不能就输出-1
pos=i;
}
}
if(pos==-1){
cout<<"-1";
return 0;
}
++ans;
t=pos+r;//更新覆盖位置最右端的位置
}
cout<<ans;
return 0;
}
G.非常可乐
题意:有一杯可乐容量为 S S S,有两个杯子容量分别为 N , M N,M N,M,可乐可以在他们之间任意倾倒,问是否两个杯子里能有等量的可乐,若能则输出倾倒的最少次数,若不能则输出NO。
解题方案:这好早之前训练写的题了,有两种方法一是bfs直接搜,二是数论证明,数论证明部分可以去看看v5zsq大大的神帖(所以学好数学行天下这句话是真不假啊)。
https://blog.csdn.net/V5ZSQ/article/details/52097459
AC代码:
#include <bits/stdc++.h>
typedef long long ll;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
using namespace std;
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int s,n,m;
while(cin>>s>>n>>m&&n){
s/=gcd(n,m);
if(s&1)cout<<"NO\n";
else cout<<s-1<<'\n';
}
return 0;
}
H.Books Queries
题意:有一书架,现在有三种操作:
1、 L L L i d id id,从左向书架中塞入一本编号为id的书
2、 R R R i d id id,从右向书架中塞入一本编号为id的书
2、 ? ? ? i d id id,从书架中取出一本编号为id的书至少需要取出多少本书先,可从左往右取也可以反过来。
题解:模拟即可,记从左塞入的书架的位置为坐标轴原点左端(包括原点),从右塞入书架的位置为坐标轴原点右端(不包括原点),取书的时候就求一下是左端到这本书的距离近还是右端。
AC代码:
#include <bits/stdc++.h>
using namespace std;
map<int,int>mp;
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int l = 0,r = 1;
int q;cin>>q;
while(q--){
char s;cin>>s;
int x;cin>>x;
if(s=='L'){
mp[x]=l--;
}else if(s=='R'){
mp[x]=r++;
}else cout<<min(mp[x]-l,r-mp[x])-1<<'\n';
}
return 0;
}
I.How many integers can you find
题意:给定一个数 N N N,然后给 m m m个数,问在小于 N N N的数里面,有多少个能被这 m m m个数整除。
解题方案:典型的容斥定理的题,请前往容斥定理,进行详细了解。然后容斥的时候需要忽略掉等于0和大于 N N N的数,然后再用二进制枚举,求容斥所得的结果,奇加偶减,即可。
AC代码:
#include <bits/stdc++.h>
using namespace std;
int n,m;
int a[15];
typedef long long ll;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
while(cin>>n>>m){
ll ans = 0;
int tot = 0;
for(int i=0;i<m;++i){
int x;cin>>x;
if(x>0&&x<n)a[tot++]=x;
}
for(int i=1;i<(1<<tot);++i){
int cnt = 0;
ll lcm = 1;
for(int j=0;j<tot;++j){
if(a[j]&&(i&(1<<j))){
++cnt;
lcm = lcm/gcd(lcm,a[j])*a[j];
}
}
if(cnt&1)ans+=(n-1)/lcm;
else ans-=(n-1)/lcm;
}
cout<<ans<<'\n';
}
}