KDY-二轮模拟-ZHX补题报告

1. 比赛情况

T1 三个T2 合体T3 矩形T4 数对总分
100pts70pts20pts20pts210pts

2.赛中概况

第一第二题比较简单,用了1小时搞定。(第一题全体AK)

第3,4题难度飙升,想了好久最后改用暴力,共得40分,符合预期。

3.题目解析


 T1 暴力出奇迹

1.1 问题描述

现在科学家在培养 A,B,C三种微生物,这三种微生物每一秒都会繁殖出新的微生物,具体规则为:

A 类微生物每一秒会繁殖出 1 个 A 类微生物,1 个 B 类微生物,1 个 C 类微生物。
B 类微生物每一秒会繁殖出 2 个 A 类微生物,2 个 C 类微生物。
C 类微生物每一秒会繁殖出 1 个 A 类微生物,1 个 B 类微生物。

假设所有的微生物都不会死亡,一开始培养皿中有 A,B,C 三种微生物各 1 个,现在问你 n 秒后 A,B,C 三种微生物分别有奇数个还是偶数个。

1.2 输入格式

从文件 three.in 中读取数据。

一行一个整数 n。

1.3 输出格式

输出到文件 three.out 中。

输出总共三行:

第一行:若 n 秒后 A 类微生物有奇数个,输出 odd,否则输出 even
第二行:若 n 秒后 B 类微生物有奇数个,输出 odd,否则输出 even
第三行:若 n 秒后 C 类微生物有奇数个,输出 odd,否则输出 even

1.4 输入样例1
  1. 3
1.5 输出样例1
  1. odd
  2. odd
  3. odd
1.6 输入样例2
  1. 4
1.7 输出样例2
  1. odd
  2. odd
  3. even
1.8 输入样例3
  1. 233
1.9 输出样例3
 
 
  1. even
  2. even
  3. odd

1.10 数据描述

总共 20 个测试点:

对于测试点 1∼4:1≤n≤3。
对于测试点 5∼8:1≤n≤100。
对于测试点 9∼20:1≤n≤10^6​​。


 

 分析

不必算出具体个数,只需判断结果为奇数或偶数即可。

AC码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100500;
int main(){
	//freopen("three.in","r",stdin);
	//freopen("three.out","w",stdout);
	ll n;
	ll a=1,b=1,c=1;  //计算奇偶数,1为奇数,2为偶数
	cin>>n;
	for(int i=1;i<=n;i++){
		ll ta=0,tb=0,tc=0;
		ta+=a;       //繁殖过程
		tb+=a;
		tc+=a;
		ta+=(2*b);
		tc+=(2*c);
		ta+=c;
		tb+=c;
		a+=ta;
		b+=tb;
		c+=tc;
		if(a%2==0)a=2;    //!!不能为0!!
		else a=1;
		if(b%2==0)b=2;
		else b=1;
		if(c%2==0)c=2;
		else c=1;
	}if(a%2)cout<<"odd\n";   //输出判断
	else cout<<"even\n";
	if(b%2)cout<<"odd\n";
	else cout<<"even\n";
	if(c%2)cout<<"odd\n";
	else cout<<"even\n";
	return 0;
}

T2 打表过样例

2.1 问题描述

现在有 nn 个大小范围在 1∼m 中的整数 a1∼an​​,并且你获得了一项魔法能力。
施加一次魔法能力后,可以将两个相同的数字合并成一个数字,并且这个数字为原来的数字 +1,例如:

有 2,2这两个数字,施加一次魔法能力后可以将这两个数字合并成一个数字 3。

现在有 q 次询问,每次询问给你一个整数 x,你可以施加任意次数魔法能力,问你这 n 个整数最多能得到多少个整数 x?

2.2 输入格式

从文件 fit.in 中读取数据。

第一行两个整数 n,m。
第二行 nn 个整数 a1∼an。
第三行一个整数 q。
接下来 q 行,每行一个整数 x。

2.3 输出格式

输出到文件 fit.out 中。

输出 q 行,对于每个询问,输出对应的答案。

2.4 输入样例
 
 
  1. 10 4
  2. 1 1 1 2 1 3 4 1 2 3
  3. 5
  4. 1
  5. 2
  6. 3
  7. 4
  8. 4
2.5 输出样例
 
 
  1. 5
  2. 4
  3. 4
  4. 3
  5. 3
2.6 数据描述

总共 20 个测试点:

对于测试点 1∼4:1≤n≤10,1≤m≤10,1≤a​i​​≤m,1≤q≤10,1≤x≤m。
对于测试点 5∼6:1≤n≤10^6,m=1,ai=1,q=1,x=1
对于测试点 7∼8:1≤n≤106,m=5,1≤ai≤m,1≤x≤m
对于测试点 9∼20:1≤n≤106,1≤m≤106,1≤ai≤m,1≤x≤m

分析:

输入数组后在定义一个大小为M的数组存储每个是最大合并个数,输出即可。(二小合一大,跟AK-IOI  死铁差不多)

 AC码:

#include<bits/stdc++.h>
using namespace std;
const int N=100500;
int n,a[1145114]={0},x,m,q;
int flag[1145114];
int main(){
	//freopen("fit.in","r",stdin);
	//freopen("fit.out","w",stdout);
	memset(flag,0,sizeof flag);
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		a[x]++;  //提前存储
	}scanf("%d",&q);
	for(int i=1;i<=m;i++){
	    flag[i]=a[i]+flag[i-1]/2;
		//  合并
	}
	for(int i=1;i<=q;i++){
		int j,cnt=0;
		scanf("%d",&j);
		printf("%d\n",flag[j]);  //直接输出
	}
	return 0;
}
/*
10 4
1 1 1 2 1 3 4 1 2 3
5
1
2
3
4
4
*/
//70pts↓
#include<bits/stdc++.h>
using namespace std;
const int N=100500;
int n,a[1145114]={0},x,m,q;
int flag[1145114];
int main(){
	//freopen("fit.in","r",stdin);
	//freopen("fit.out","w",stdout);
	memset(flag,-1,sizeof flag);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>x;
		a[x]++;
	}cin>>q;
	for(int i=1;i<=q;i++){
		int j,cnt=0;
		cin>>j;
		if(flag[j]!=-1){
			cout<<flag[j]<<"\n";
			continue;
		}for(int k=1;k<j;k++){
			cnt+=a[k];
			cnt/=2;
		}flag[j]=cnt+a[j];
		cout<<flag[j]<<"\n";
	}
	return 0;
}

T3 图论背模板

3.1 问题描述

现在给你一个 n 行 m 列的矩阵,矩阵上每个格子有一个整数,其中第 i 行第 j 列对应的格子上的整数为 gi,j。
现在定义该矩阵的一个子矩阵的快乐值为该子矩阵上的所有数字的异或和。

一组数字 a1,a2,...,an的异或和为 a1 xor a2 xor ... xor an(其中 xor表示按位异或运算)

现在问你,该矩阵的所有子矩阵的快乐值之和为多少?

3.2 输入格式

从文件 matrix.in 中读取数据。

第一行两个整数 n,m。
接下来 n 行,每行 m 个整数,表示该矩阵。

3.3 输出格式

输出到文件 matrix.out 中。

一行一个整数,表示答案。

3.4 输入样例

 
 
  1. 5 4
  2. 3 2 1 2
  3. 3 3 5 5
  4. 8 7 3 6
  5. 1 1 1 1
  6. 2 3 9 9
3.5 输出样例
 
 
  1. 822
3.6 数据描述

总共 20 个测试点:

对于测试点 1∼4:1≤n,m≤10,0≤gi,j<210。
对于测试点 5∼6:1≤n,m≤300,gi,j=1。
对于测试点 7∼12:1≤n,m≤300,0≤gi,j≤1。
对于测试点 13∼20:1≤n,m≤300,0≤gi,j<210​​。

 

你想AK-IOI吗?

你想毁灭一颗恒星吗?

分析:

利用前缀和的方法,定义两个数组,用来存储各个矩形的异或值,再求和即可。

AC码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100500;
ll n,m;
ll x[114514],xo[191981],a[1145][1919],ans=0;//q[1145][1919]={0};
int main(){
	//freopen("matrix.in","r",stdin);
	//freopen("matrix.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=n;i++){ 
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
		}
	}for(int sx=1;sx<=n;sx++){
		memset(x,0,sizeof x);
		for(int ex=sx;ex<=n;ex++){
			for(int j=1;j<=m;j++){
				x[j]=x[j]^a[ex][j];
				xo[j]=xo[j-1]^x[j];
			}for(int i=0;i<10;i++){
				int cnt0=1,cnt1=0;
				for(int k=1;k<=m;k++){
					if(xo[k]&(1<<i)){
						ans+=1ll*(1<<i)*cnt0;
						cnt1++;
					}else{
						ans+=1ll*(1<<i)*cnt1;
						cnt0++;
					}
				}
			}
		}
	}cout<<ans;
	return 0;
}//暴力↓ 20pts
/*#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100500;
ll cnt=0,n,m;
ll a[1145][1919];//q[1145][1919]={0};
int main(){
	//freopen("matrix.in","r",stdin);
	//freopen("matrix.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=n;i++){ 
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
			//if(i==1&&j==1)q[i][j]=a[i][j];
			//else{
			//	q[i][j]=(q[i-1][j]^q[i][j-1]^q[i-1][j-1])^a[i][j];
			//}
		}
	}for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			for(int k=i;k<=n;k++){
				for(int l=j;l<=m;l++){
					ll num=0;
					for(int x=i;x<=k;x++){
						for(int y=j;y<=l;y++){
							if(x==i&&y==j)num+=a[x][y];
							else num=num^a[x][y];
						}
					}cnt+=num;
				}
			}
		}
	}cout<<cnt;
	return 0;
}
/*#include<iostream>
using namespace std;
int main() {
    int m,n;
    cin>>m>>n;
    int matrix[m][n];
    for(int i=0;i<m;i++) {
        for(int j=0;j<n;j++) {
            cin>>matrix[i][j];
        }
    }int dp[m][n];
    dp[0][0]=matrix[0][0];
    for(int i=1;i<=m;i++) {
        for(int j=1;j<=n;j++) {
            dp[i][j]=dp[i-1][j]^dp[i][j-1]^matrix[i][j];
        }
    }long long sum=0;
    for(int size=1;size<=min(m,n);size++) {
        for(int i=0;i+m-size-1<m;i++) {
            for(int j=0;j+n-size-1<n;j++) {
                sum+=dp[i+m-size-1][j+n-size-1];
            }
        }
    }cout<<sum;
    return 0;
}*/

T4 

数论只会GCD,枚举茫然TLE。递归递推伤不起,无奈打表MLE。分治做得像枚举,带上高精才AC。

4.1 问题描述

给你一个长度为 nn 的数列 a1,a2,...,ana​1​​,a​2​​,...,a​n​​。
再给你一个长度为 mm 的数列 b1,b2,...,bmb​1​​,b​2​​,...,b​m​​。
现在再再再给你一个正整数 pp,让你生成一个长度为 n×mn×m 的数列 c1,c2,...,cn×mc​1​​,c​2​​,...,c​n×m​​。
其中满足 c(i−1)×m+j=(ai+bj) mod pc​(i−1)×m+j​​=(a​i​​+b​j​​) mod p。
现在问你数列 cc 中有多少个数对 (i,j)(i,j) 满足 i<ji<j 且 ci>cjc​i​​>c​j​​?

4.2 输入格式

从文件 pair.in 中读取数据。

第一行两个整数 n,m,pn,m,p。
第二行 nn 个整数,表示 a1∼ana​1​​∼a​n​​。
第三行 mm 个整数,表示 b1∼bmb​1​​∼b​m​​。

4.3 输出格式

输出到文件 pair.out 中。

一行一个整数,表示答案。

4.4 输入样例

 
 
  1. 6 7 10
  2. 1 1 4 5 1 4
  3. 1 9 1 9 8 1 0

4.5 输出样例

 
 
  1. 294
4.6 数据描述

总共 20 个测试点:

对于测试点 1∼4:1≤n,m≤100,1≤p≤10,0≤ai,bi<p
对于测试点 5∼6:1≤n,m≤1000,1≤p≤10,0≤ai,bi<p
对于测试点 7∼8:1≤n,m≤1000000,p=2,0≤ai,bi<p
对于测试点 9∼20:1≤n,m≤1000000,1≤p≤10,0≤ai,bi<p

分析:

第一眼 暴力!!!

看了数据范围后: 放弃吧!

最后发现p<=10,一线生机!

既然<=10,那我们完全可以找找规律·                                                       。

分析→→→→→→→→→→→→→→→→→→→→→→→→→→

WA是一种绝望。                                                                      ↓

TLE是一种痛苦,RE是一种放弃。                                           ↓

UKE是一种无奈,AC是一种原谅。                                           ↓

AC码:                                                                            ↓

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+5, M=1e6+5;
bool flag=0;//特殊样例全0
int n, m, p, a[M], b[M];
ll num[10], numb[M], nixu[10];//nixu[i]表示b数组+i之后的逆序对个数
ll ans[200], cnt=0;
void jia(ll k){
    ans[0]+=k;
    int pos=0;
    while(1){
        if(ans[pos]>=1000000){//压位高精,一个变量存6位,不再存1位
            ans[pos+1]+=ans[pos]/1000000;
            ans[pos]%=1000000;
            if(++pos>cnt){
                cnt++;
            }
        }
        else break;
    }
}
int main(){
    cin >> n >> m >> p;
    for(int i=1; i<=n; i++) {
        cin >> a[i];
        if(a[i]!=0) flag=1;
    }
    for(int i=1; i<=m; i++){
        cin >> b[i];
        if(b[i]!=0) flag=1;
        numb[b[i]]++;
    }
    //预处理,nixu[i]存储a[i]加到b[1]~b[m]各个数上的逆序对数
    for(int j=0; j<p; j++){//a、b数组范围在0~9,打表预处理,
        memset(num, 0, sizeof num);
        for(int i=1; i<=m; i++){//枚举b
            for(int k=b[i]+1; k<p; k++){//k=b[(i+j)%p]+1;
                //保证数字比b[i]大
                nixu[j] += num[k];
            }
            num[b[i]]++;//num[(i+j)%p]++;
            //记录b[i]次数,为下次循环准备
            b[i]=(b[i]+1)%p;//注释掉
            //保证自增,代替掉模拟a[i]+b[j]的枚举,因为a、b数组元素皆<p
        }
    }
    memset(num, 0, sizeof num);
    //ll ans=0;
    for(int i=1; i<=n; i++){
        //ans+=nixu[a[i]];//块内的逆序对数量,c[(i-1)%m+1]~c[(i-1)*m+m]
        jia(nixu[a[i]]);
        for(int j=0; j<p; j++){
            int x=(j+a[i])%p;//某一个c的值
            for(int k=x+1; k<p; k++){
                //ans+=1ll*numb[j]*num[k];
                //块与块之间的个数(nm太大只能求块与块加、间的),不做优化30
                ll x=1ll*numb[j]*num[k];
                jia(x);
            }
        }
        for(int j=0; j<p; j++){
            num[(j+a[i])%p]+=numb[j];
        }
    }
    if(!flag) cout << 0;
    else{
        cout << ans[cnt];
        for(int i=cnt-1; i>=0; i--){
            printf("%06lld", ans[i]);
        }
    }
    return 0;

如果你觉得这道题很简单的话,点这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值