8.12做题总结

1.题目背景

蒜头君发现了一本古老的魔法书,书中记载了一个神奇的数字游戏。游戏中,蒜头君从数字0出发,可以进行n次魔法跳跃。每一次跳跃,他可以选择向前跳1步(+1)或者向后跳1步(-1)。蒜头君想知道,通过这n次跳跃,他是否能刚好跳到一个神秘的数字m上,完成一次不可思议的冒险旅程。

帮助蒜头君判断,给他n次跳跃机会,从0开始,能否恰好跳到数字m上。如果可以,就大声地告诉他“Yes”让他满怀信心的开始这次冒险;如果不可以,就要温柔地告诉他“No”,并且鼓励他尝试下一次挑战。

输入格式

输入一行包含两个正整数n和m。

输出格式

输出Yes或者No。

数据范围

对于40%的数据,1≤n,m≤101≤n,m≤10;

对于100%的数据,n,m在int范围内,并且均为正整数;

简单的找规律 假设n比m小 肯定到不了 n大于m时 判断n-m为偶数可以到达 奇数不行

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,m;
    cin>>n>>m;
    if(n==m){
        cout<<"Yes"<<endl;
    }
    else if(n-m>0&&(n-m)%2==0){
        cout<<"Yes"<<endl;
    }
    else cout<<"No"<<endl;
    return 0;
}

2.

在蒜头王国的智慧宫殿里,蒜头君发现了一张古老而神秘的藏宝图,这张藏宝图被巧妙地隐藏在一个特殊的矩阵之中。为了找到隐藏的宝藏,蒜头君需要按照一种独特的路径揭示举证中的秘密数字。现在他需要你的智慧和帮助!

想象你站在一个神奇的矩阵迷宫入口,这个矩阵共有n行n列(n<=20),里面藏有指引至宝藏的关键数字。你的任务是从矩阵的左上角(1,1)位置出发,按照特定的路线输出数字。具体来说:

1.首先,你将沿着主对角线向右下方移动,每次尝试连续输出n个数字,从数字1开始,顺次填写完1到n2n2的所有数字。

2.接下来,你的操作将全在与主对角线平行的矩阵斜线上,如果你在某条矩阵斜线上输出n哥数字,那么你就将顺着往下一个与主对角线平行的矩阵斜线去填充接下来的n哥数字,直到把矩阵填满。当然,你有时可能无法再一条斜线上完成连续输出n个数字,则按照以下规则。

3.当在某个矩阵斜线上无法一次性输出n个数字的话,如果此时处于矩阵的下三角形,你将会从上三角区域最右上角未填充数字的矩阵斜线开始进行填充数字,如果你此时处于矩阵的上三角区域,你将会从下三角区域最右上边未填充数字的矩阵斜线开始进行填充数字。

例如,在一个4*4的矩阵中,你最后输出的矩阵可能会像这样:

1 14 9 8

5 2 15 10

11 6 3 16

13 12 7 4

我们对于这个4*4的矩阵,首先填写1到4四个数字,填入主对角线上,恰好填满,接着顺着填充下一条与主对角线平行的矩阵斜线,需要一口气填入5到8四个数字,但是下一条矩阵斜线上只有3个数字可以填充,无法填充慢,因此根据规则往上三角区域的未填充数字的矩阵斜线进行填充,刚好填充完毕,接下来继续填充9到12四个数字,顺着填充结束的8所在的矩阵斜线的下一个矩阵斜线去填充,由于下一个矩阵斜线只有2个数字可以填充,然后更具规则往下半三角区域矩阵斜线进行填充,依此类推,最终填充完毕。

输入格式

输入为一行包含一个整数n。

输出格式

输出一个n*n的矩阵。

数据范围

对于25%的数据,1≤n≤51≤n≤5;

对于50%的数据,1≤n≤101≤n≤10

对于100%的数据,1≤n≤201≤n≤20

模拟题

#include<bits/stdc++.h>
#define int long long
using namespace std;
 main(){
	int n;
	cin>>n;
	int mp[22][22];	
	int temp=0;
	memset(mp,0,sizeof(mp));
	for(int i = 1;i<=n;i++){
		mp[i][i]=i;
	}
	if(n>=2){
		mp[1][n]=2*n;
	}
	for(int i = 2;i<=n;i++){
		mp[i][i-1]=n+i-1;
	}
	for(int i = n-1;i>0&&i<=n&&n>=3;i++){
		mp[i+2-n][i]=n+i+2;
	}
	for(int i = 3;i<=n;i++){
		mp[i][i-2]=n+n+i; 
	}
	for(int i = 4;i<=n;i++){
		mp[i][i-3]=3*n+i-3;
		temp=mp[i][i-3];
	}
	for(int i = n-2;i<=n&&n>=4;i++){
			temp++;
	mp[i+3-n][i]=temp;
	}
	for(int i = n-3;i<=n&&n>=5;i++){
		temp++;
		mp[i+4-n][i]=temp;
	}
	for(int i = 5;i<=n;i++){
		temp++;
		mp[i][i-4]=temp;
	}
	for(int i = 6;i<=n;i++){
		temp++;
		mp[i][i-5]=temp;
	}
	for(int i =n-4;i<=n&&n>=6;i++){
		temp++;
		mp[i+5-n][i]=temp;
	}
		for(int i =n-5;i<=n&&n>=7;i++){
		temp++;
		mp[i+6-n][i]=temp;
	}
	for(int i = 7;i<=n;i++){
		temp++;
		mp[i][i-6]=temp;
	}
	for(int i = 8;i<=n;i++){
		temp++;
		mp[i][i-7]=temp;
	}
		for(int i =n-6;i<=n&&n>=8;i++){
		temp++;
		mp[i+7-n][i]=temp;
	}
		for(int i =n-7;i<=n&&n>=9;i++){
		temp++;
		mp[i+8-n][i]=temp;
	}
	for(int i = 9;i<=n;i++){
		temp++;
		mp[i][i-8]=temp;
	}
	for(int i = 10;i<=n;i++){
		temp++;
		mp[i][i-9]=temp;
	}
		for(int i =n-8;i<=n&&n>=10;i++){
			
		temp++;
		mp[i+9-n][i]=temp;
	}
		for(int i =n-9;i<=n&&n>=11;i++){
		temp++;
		mp[i+10-n][i]=temp;
	}
	for(int i = 11;i<=n;i++){
		temp++;
		mp[i][i-10]=temp;
	}
	for(int i = 12;i<=n;i++){
		temp++;
		mp[i][i-11]=temp;
	}
		for(int i =n-10;i<=n&&n>=12;i++){
		temp++;
		mp[i+11-n][i]=temp;
	}
	for(int i =n-11;i<=n&&n>=13;i++){
		temp++;
		mp[i+12-n][i]=temp;
	}
	for(int i = 13;i<=n;i++){
		temp++;
		mp[i][i-12]=temp;
	}
	for(int i = 14;i<=n;i++){
		temp++;
		mp[i][i-13]=temp;
	}
	for(int i =n-12;i<=n&&n>=14;i++){
		temp++;
		mp[i+13-n][i]=temp;
	}
	for(int i =n-13;i<=n&&n>=15;i++){
		temp++;
		mp[i+14-n][i]=temp;
	}
	for(int i = 15;i<=n;i++){
		temp++;
		mp[i][i-14]=temp;
	}
	for(int i = 16;i<=n;i++){
		temp++;
		mp[i][i-15]=temp;
	}
	for(int i =n-14;i<=n&&n>=16;i++){
		temp++;
		mp[i+15-n][i]=temp;
	}
	for(int i =n-15;i<=n&&n>=17;i++){
		temp++;
		mp[i+16-n][i]=temp;
	}
	for(int i = 17;i<=n;i++){
		temp++;
		mp[i][i-16]=temp;
	}
	for(int i = 18;i<=n;i++){
		temp++;
		mp[i][i-17]=temp;
	}
	for(int i =n-16;i<=n&&n>=18;i++){
		temp++;
		mp[i+17-n][i]=temp;
	}
		for(int i =n-17;i<=n&&n>=19;i++){
		temp++;
		mp[i+18-n][i]=temp;
	}
		for(int i = 19;i<=n;i++){
		temp++;
		mp[i][i-18]=temp;
	}
	for(int i = 20;i<=n;i++){
		temp++;
		mp[i][i-19]=temp;
	}
		for(int i =n-18;i<=n&&n>=20;i++){
		temp++;
		mp[i+19-n][i]=temp;
	}
	for(int i =n-19;i<=n&&n>=21;i++){
		temp++;
		mp[i+20-n][i]=temp;
	}

if(n==21){
	mp[21][1]=441;
}
for(int i = 1;i<=n;i++){
	for(int j=1;j<=n;j++){
		cout<<mp[i][j]<<" ";
	}
	cout<<endl;
	
}
return 0;
}

中间重复部分可以写一个循环来代替

3.

题目背景

在蒜头小镇的科技庆典上,蒜头君设计了一个名为“数字侦探”的趣味游戏,吸引了众多小伙伴参与。游戏中,蒜头君准备了一个正整数数组,里面藏有许多神秘的数字线索。每位小侦探面临的挑战是,根据给出的查询要求,追踪特定数字在过去出现的位置。

你将获得一个由不超过105105范围的正整数组成的列表nums,该列表下标从1开始,列表的长度不会超过106106。接下来,会有一系列的查询请求到来,每个请求以形式x y给出,意味着你需要查找数字y最后一次出现在位置x之前的下标。

比如,如果nums=[1,2,3,2,5],当查询为3 2时,因为2在位置3之前最后一次出现在位置2,所以答案是2。但如果之前没有出现过y,则输出-1。

作为蒜头君邀请的小小侦探,你的目标是快速响应每一个查询,精准找出或确定数字y在指定位置x之前最后一次现身的位置下标,揭开隐藏在数组背后的秘密。

输入格式

第一行包含两个整数n和m,表示数组的长度和询问的次数。

第二行包含n个整数,表示数组的n个元素。

姐姐下来m行包含m次询问,操作输入格式为: x y,表示你需要查找数字y最后一次出现在位置x之前的下标。如果不存在,则输出-1。

输出格式

输出m行,对于每次询问输出答案。

数据范围

对于40%的数据,1≤n,m≤101≤n,m≤10;

对于60%的数据,1≤n,m≤10001≤n,m≤1000,保证每个数的出现次数不超过10次;

对于100%的数据,1≤n,m≤10000001≤n,m≤1000000。

给你一个数组n,用vector容器开一个hx数组 下标为出现的数字 数字存储的数字为他出现的位置 最后在询问时用二分查找 答案输出用三目运算符和读写加入 刚好能在时间内跑完

#include<bits/stdc++.h>
using namespace std;
const int N = 10e5+10;
int n,m;
vector<int> hx[N];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    cin>>n>>m;
    for(int i = 1;i<=n;i++){
        int t;
        cin>>t;
        hx[t].push_back(i);
    }
    while(m--){
    int a,b;
    cin>>a>>b;
    int    ans=-1;
        int l=-1;
    int r=hx[b].size();
    while(l+1<r){
        int mid=l+r>>1;
        if(hx[b][mid]<a){
            l=mid;
        }
        else r=mid;
    }
    
        cout << (l == -1 ? -1 : hx[b][l]) << "\n";
    }
    return 0;
    
}

4.

题目背景

在蒜头王国的魔法学院里,蒜头君发现了一项古老的魔法实验——“极光之选”。这项试验要求利用一个充满魔力的数组,通过精心挑选出k段特定长度的子数组,来汇聚最大的魔法能力,电亮整个魔法阵。现在,蒜头君诚邀你一同参与这项激动人心的挑战!

你面前摆放着一个由n个魔力值组成的数组,每个元素代表着该位置的魔力强度。你的任务是选择k段长度均为m的连续子数组(这些子数组互不重叠),每段子数组的魔力值之和将被雷击,以期达到最大的累积魔力值,从而激活“极光之选”的终极魔法。

你的魔法任务是运用你的智慧,设计一种策略,选取k段长度为m的魔力数组,使得这些子数组的魔力值之和最大化。计算并告知蒜头君,通过最优选择,所能达到的最大累积魔力值是多少。

注意:

1.数组长度n与子数组长度m均符合实际魔法操作的限制。

2.确保所选的每段子数组互不重叠,即任意两段子数组之间没有共同的元素。

输入格式

第一行包含三个整数n和m和k。

第二行包含n个整数,代表魔力值数组的魔力值。

输出格式

输出最终的要求答案

数据范围

对于40%的数据,1≤m∗k≤n≤5001≤m∗k≤n≤500,魔力值在int范围内且为正整数;

对于100%的数据,1≤m∗k≤n≤50001≤m∗k≤n≤5000,魔力值在int范围内且为正整数;

求k个m长度的子序列的和最大,用动态规划 dpij i表示当前是第几个 j表示当前取到第几个子序列(注意序列不能重叠)

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int n, m, k;
    cin >> n >> m >> k;
    vector<ll> a(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        a[i] += a[i - 1];
    }
    vector<vector<ll>> f(n + 1, vector<ll>(k + 1));
    ll ans = 0;
    for (int i = m; i <= n; i++) {
        f[i] = f[i - 1];
        for (int j = 0; j < k; j++) {
            f[i][j + 1] = max(f[i][j + 1], f[i - m][j] + a[i] - a[i - m]);
            ans = max(ans, f[i][j + 1]);
        }
    }
    cout << ans << "\n";
    return 0;
}

P1419 寻找段落

题意给你一个序列长度为n 给你一个范围s到t让你在这个范围内找价值最大,也就是长度为s到t的序列和/他们的长度 得到的值最大,由题意可知答案是单调的,我们可以二分得到答案再用滑动窗口确定答案是否可行,他的误差说是1e-3,不知道为啥 1e-5才能过 1e-4会被卡掉一个点

#include<bits/stdc++.h>
using namespace std;
int n,s,t;
double a[100005];
double ans;
double check(double l,double r){
	if(l>r-1e-5){
		ans=r;
		return 0;
	}	
	double mid=(l+r)/2;
	double b[100005],sum[100005];
	int hh=1,tt=0;
	int q[100005];
	for(int i=1;i<=n;i++){
		b[i]=a[i]-mid; 
		sum[i]=sum[i-1]+b[i];
	}
	for (int i=1;i<=n;i++){	
        if(i>=s){
            while(tt>=hh&& sum[i-s]<sum[q[tt]])tt--;
            q[++tt]=i-s;
        }
        if(hh<=tt&& q[hh]<i-t) hh++;
        if(hh<=tt&& sum[i]-sum[q[hh]]>=0) return check(mid,r);
    }
    return check(l,mid);
}
int main()
{
	cin>>n>>s>>t;
	for(int i=1;i<=n;i++){
	cin>>a[i];	
	}
	check(-10010,10010);
	printf("%.3lf",ans);
	return 0;
}

P1494 [国家集训队] 小 Z 的袜子

题意给你长度为n的数组 数字每个数字代表一种颜色的袜子,然后m次询问 每次询问给出l,r找到这个范围时随机抽出两个袜子的颜色相同的概率 输出A/B为最简分数;

每次询问是l,r范围,l是left左端点,r是right右端点 如果每次都暴力肯定会超时 我们可以想假设他l,r是按照顺序排序 这样我们从大到小或者从小到大是不是只需要遍历n个数字

但是他不是按照顺序,那我们定义一个顺序,假设他们分为很多个块 每个块的大小是n的开方

我们把每个l根据他们的大小给每个id分他们属于第几个块,如果块相同就用r比较不同就用l来比较

我们用结构体来存l,r和id id表示他的输出顺序 方便我们通过id得到ans

我们用block来存每个id的块 c表示每个位置的颜色

排序之后对每一个进行暴力 将当前的l,r移动到最近的询问的l,r每次移动修改

显然 答案是一个分数 我们将其分开讨论 分母是(r-l)x(r-l+1),分子是所有能成对的袜子的数量x他的数量-1

假设我们有6个袜子 里面是1 2 3 3 3 1

那我们一共有6x5种情况

然后可以取到的情况是拿袜子颜色3的 3*2拿袜子颜色1的 2*1拿袜子颜色2的1*0;

将这些加起来得到分子

所以下面对循环进行处理

当范围变大的时候 对于新的点c 我们减去该点c的乘积 然后给该点c加1 再加上他的乘积 比如上面的例子 我们从6个袜子变成七个袜子 1 2 3 3 3 1 3

此时减去 3*2 给c【3】+1 然后乘= 4*3 重新加上

相反当范围变小的时候 我们还是减去该点的乘积 然后给他的c减去一 再加上乘积;

最后分子分母约分 然后将答案存入ans【id】 0表示分子 1表示分母

#include<bits/stdc++.h>
using namespace std;
const int N = 500005;
int block[N];
int c[N];
struct query{
    int l, r, id;
    bool operator <(const query &q1){
        if(block[l]==block[q1.l])return r<q1.r;
        else return l<q1.l;
    }
}q[N];
int main(){
    int n,m;
    cin>>n>>m;
    int ans[m+1][2];
    int sq=sqrt(n);
    int a[n+1];
    a[0]=0; 
    for(int i = 1;i<=n;i++){
        cin>>a[i];
    }
    for(int i = 1;i<=m;i++){
        cin>>q[i].l>>q[i].r;
        q[i].id=i;
        block[q[i].l]=(q[i].l-1)/sq +1;
    }
    sort(q+1,q+1+m);
    int t=0,h=1;
    long long fz=0;
    c[a[1]]=1;
    c[a[0]]=1;
    for(int i = 1;i<=m;i++){
        while(h<q[i].r){
            h++;
            fz-=c[a[h]]*(c[a[h]]-1);
            c[a[h]]+=1;
            fz+=c[a[h]]*(c[a[h]]-1);
        }
        while(h>q[i].r){
            fz-=c[a[h]]*(c[a[h]]-1);
            c[a[h]]-=1;
            fz+=c[a[h]]*(c[a[h]]-1);
            h--;
        }
        while(t<q[i].l){
            fz-=c[a[t]]*(c[a[t]]-1);
            c[a[t]]--;
            fz+=c[a[t]]*(c[a[t]]-1);
            t++;
        }
        while(t>q[i].l){
            t--;
            fz-=c[a[t]]*(c[a[t]]-1);
            c[a[t]]+=1;
            fz+=c[a[t]]*(c[a[t]]-1);
        }
    if(q[i].l!=q[i].r){
    long long temp=(long long)q[i].r-q[i].l;
    long long fm=temp*(temp+1);
        ans[q[i].id][0]=(long long)fz/__gcd(fz,fm);
        ans[q[i].id][1]=(long long)fm/__gcd(fz,fm);
    }
    else{
        ans[q[i].id][0]=0;
        ans[q[i].id][1]=1;
    }
    }
    for(int i = 1;i<=m;i++){
        cout<<ans[i][0]<<'/'<<ans[i][1]<<endl;
    }
    
    return 0;
    
}

P6187 [NOI Online #1 提高组] 最小环

给你一个环,和一个序列a【n】,该序列可以任意填到环上 然后发出m次询问每次给一个k

表示求所有的a【i】和他相邻k个数的和,

我们可以用贪心的思想来看一下 比如 1 2 3 4 5 6这个数组 假设k为0 答案为所有数的平方和 

当k为1的时候,  6是不是要和5乘才是最大 4是不是要和6乘才是最大,假设4和5乘 他们会多一个5 少一个6,所以最终的排序是  1 2 4 6 5 3;他们只会形成一个环

如果是k=2的时候 他就会形成这样两个环  我们把大的数放一起 小的数放一起 6 3 5 2 4 1;

直观一点 是6 5 4 三个数分别相乘 3 2 1 三个数分别相乘

综上我们可以找到一个规律

首先我们将数组进行排序,然后求一个他们的最大公约数,即他们能成为多少个环,当成环的数量相同的时候 他们的答案也是一样的。

#include<bits/stdc++.h>
using namespace std;
int main(){
	long long n,m;
	cin>>n>>m;
	long long a[n+1];
	long long sum=0;
	for(int i = 1;i<=n;i++){
		cin>>a[i];
		sum+=a[i]*a[i];
	}
	sort(a+1,a+1+n,greater<int>());
	long long ans[n];
	memset(ans,0,sizeof(ans));
	ans[0]=sum;
	for(int i = 1;i<=m;i++){
		long long k;
		cin>>k;
		if(k==0){
			cout<<ans[0]<<endl; 
		}
		else{
		long long temp=0;
			if(ans[__gcd(k,n)]!=0){
				cout<<ans[__gcd(k,n)]<<endl;
			}
			else{
				long long t=__gcd(k,n);
				long long cnt=0;
				for(int i = 1;i<=t;i++){
					for(int j =(i-1)*(n/t)+1;j+1<=(i-1)*(n/t)+n/t;j++){
						if(j==(i-1)*(n/t)+1&&n/t>2){
							temp+=a[j]*a[j+1];
							temp+=a[j]*a[j+2];
						}
						else if(j==(i-1)*(n/t)-1+(n/t)&&n/t>2){
							temp+=a[j]*a[j+1];
						}
						else if(n/t>2&&j>(i-1)*(n/t)+1&&j<(i-1)*(n/t)-1+n/t){
							temp+=a[j]*a[j+2];
						}
						if(n/t==2){
							temp+=a[j]*a[j+1];
						}
					}
				}
			ans[__gcd(k,n)]=temp;
			if(n/t==2)cout<<2*ans[__gcd(k,n)]<<endl;
			else cout<<ans[__gcd(k,n)]<<endl;
			}
		}
		
	}
	
	
	return 0;
	
} 

不知道为啥wa了3个点 今天先写到这里 明天再改


  • 19
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值