暑训第三场

A.Creating the Contest

题意:给你一串递增的数字,要你从中选取子序列,满足子序列的每个元素都满足 a i + 1 ≤ a i ∗ 2 a_{i+1}\le a_i*2 ai+1ai2 ,问这个子序列的最大长度。

解题思路:明显可以看出,这个子序列肯定是连续的,举个例子,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(n1)(n2),如果是偶数,只需要讨论一下, n n n n − 3 n-3 n3是否互质,然后再看 n − 1 n-1 n1是奇数,按奇数的求法求个值,再求两者的最大值就行了。

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] [posr+1,pos+r1]的位置都被暖气充盈,问是否能使暖气充满整个数组,若不能输出-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';
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值