网监系2021届校赛题解代码

这篇博客展示了各种数学和算法问题的解决过程,包括求和序列、偶数世界的质数、字符串处理、动态规划、图论、全等三角形判断等。每个问题都附带了简洁的C++代码实现,从简单到复杂,逐步提升难度,适合对数学和算法感兴趣的读者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、阿美的公式

题目连接

张三今天上自习课的时候,
发现他的同学小美在做一道数学题: 1 + 1/2 - 1/4 + 1/8 – 1/16 + 1/32 – 1/64 + … + 1/n
张三非常喜欢小美,本想去表现一波,但是奈何自己没学好数学,
于是乎,张三向你发送了请求,请你帮助张三完成题目,好让他好好去表现一波!!!
(结果保留6位小数)

题解:

  • 这真没说的哈,自己看自己看。
#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    cin >> n;
    double res = 1;
    int f = 1;  // 计算到第几个 
    int k = 1;  // 转变符号 
    
    while(1){
        f *= 2;
        res += 1.0 / f * k;
        k *= -1;
        if(f == n)break;
    }
    //printf("%.6lf", res);    
    cout<<fixed<<setprecision(6)<<res<<endl;   // c++ 输出小数方式
}




二、偶数的世界

题目连接

欢迎来到偶数的世界。偶数世界是这样一个世界:这个世界里只有偶数。在偶数世界中,整数的集合是:{…, -4, -2, 0, 2, 4, …}。正整数的集合是{2, 4, …}。显而易见,偶数世界中的整数集合对加、减、乘都是封闭的。同样,偶数世界里也有整除的概念。例如:4可以整除8,而6不能被2整除。

既然有了整除,也可以有质数的概念。在偶数世界中,没有任何因子的数被称为质数。例如2是一个质数,6是另外一个质数,而8是一个合数。你的任务是求出偶数世界中的第k个质数。我们认为2是偶数世界中的第1个质数。

题解:

  • 这个其实就是一个找规律的题目,当然啦,咋还是得把题目意思看懂,做的多了,这种规律就自然而然会了。。。。
  • 记得是多次数据输入哈!!
#include <bits/stdc++.h>
using namespace std;

int main(){
    long long n;
    // while(~scanf("%d",&n){     c语言写法
    while(cin >> n){
        cout << 2 + (n - 1) * 4 << endl;
    }
    return 0;
}




三、一模一样

题目连接

为了防止有人在校赛中剃光头,所以我们要出一道简单的题。但是题名为什么不用“简单的题”呢?因为这道题其实没那么简单。

  • 注意,多组数据输入,而且,我们从第一组和第二组测试样例中可以看出,只能使用string类型哈!
#include<bits/stdc++.h>
using namespace std;
int main(){
	string s;
	while(cin >> s){
		cout << s << endl;	
	}
	return 0;
}




四、神之洞察术

题目连接

  • 因为有进万组的测试样例,所以我们不可以每次输入值都进行计算一次,我们可以先预处理一波!
#include<bits/stdc++.h>
using namespace std;

int D[10001] = {1,1,2};
int T[10001] = {1,2,4};

void dp(){
	for(int i=3;i<10001;++i){
		D[i] = ( D[i-1] + D[i-2] ) % 2017;
		T[i] = ( i + 1 ) * D[i-1] % 2017 + (D[i-2]<<1) % 2017;
		T[i] %= 2017;
	}
}

int main(){
	dp();
	int n;
	while(cin>>n) cout<<T[n-1]<<endl;
	return 0;
}




五、神之重叠术

题目连接

图G是(V, E)的二元组,其中V表示顶点的集合,E表示边的集合。每一条边使用一个点对表示。此处仅考虑无向边,即点对的顺序并不重要。

如果一对顶点之间(未必是相异顶点),存在多条边,则称这些边为平行边,平行边的条数称为重数。在一个图中,重数最大的顶点对的重数,称之为图的重数。

给定一个图,求其重数。

  • 就是一个无向图,然后给出m条边,把重复数最多的数量输出即可,嘤嘤嘤
  • 好好学好好看,这里我们使用map+pair方式进行存储记录,轻松又方便
#include<bits/stdc++.h>
using namespace std;
map<pair<int,int>,int>mp;
int main(){
	int n,m;
	int a,b;
	
	while(cin >> n >> m){
		int ans = 0;  // 用于记录最大的边数 
		while(m--){
			cin >> a >> b;
			if(a>b){
				int t = a; a = b; b = t;  // 交换,保证a小于b 
			}
			mp[{a,b}]++;
			ans = max(ans , mp[{a,b}]) ;
		}
		cout << ans << endl;
	}
	return 0;
}




六、神规

题目连接

合法的域名规则如下:

(1)一个完整的域名由若干级子名组成,每个子名之间用点号分隔。

(2)每个子名是一个长度在[1, 63]之间的字符串。

(3)每个子名由52个英文字母以及10个数字构成,且数字不能作为开头。

(4)同一个域名之间的不同级子名不能重复。

  • 这个就是按照规则来,一个一个匹配上就好啦,有点长,但是不用太动脑
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 +10;
int pos[N];
string str = "hunnu.edu.cn";
set<string>f;
string s[3] = {"hunnu", "edu", "cn"};
int main(){
    string ss;
    while(cin >> ss){
        int cnt = 0;
        if(ss.size() < 13){
            cout << "NO" <<endl;
        }
        else{
            if(ss.substr(ss.size() - 12, 12) != str){
                cout << "NO" <<endl;
            }
            else{
                bool flag = true;
                for(int i = 0; i < ss.size() - 12; i ++){
                    if(ss[i] == '.')
                        pos[++ cnt] = i;
                    else{
                        if((ss[i] < '0' || ss[i] > '9') && (ss[i] < 'A' || ss[i] > 'Z') && (ss[i] < 'a' || ss[i] > 'z'))
                            flag = false;
                    }
                }
                if(ss[ss.size() - 13] != '.')flag = false;
                if(!flag){
                    cout << "NO" <<endl;
                    continue;
                }
                f.clear();
                for(int i = 0 ;i < 3; i ++)
                    f.insert(s[i]);
                int j = 0;
                for(int i = 1; i <= cnt ;i ++){
                    if(pos[i] - j <= 0 || pos[i] - j > 63){
                        flag = false;
                        break;
                    }
                    else{
                        if(ss[j] >= '0' && ss[j] <= '9'){
                            flag = false;
                            break;
                        }
                        if(f.count(ss.substr(j, pos[i] - j))){
                            flag = false;
                            break;
                        }
                        f.insert(ss.substr(j, pos[i] - j));
                    }
                    j = pos[i] + 1;
                }
                if(flag)
                    cout << "YES" << endl;
                else cout << "NO" << endl;
            }
        }
    }
}




七、神一样的队友

题目连接

  • Dinic算法,这个需要对图有较深的了解哈,别问,俺这个做不出来,嘤嘤嘤
#include <stdio.h>
#include <algorithm>
using namespace std;

//type of edge's weight
typedef int weight_t;

//just as its names
int const SIZE_OF_VERTICES = 30010;
int const SIZE_OF_EDGES = 50010;

struct edge_t{
	int from,to;
	weight_t weight;
	int next;//Index of the array is used as pointers, ZERO means NULL
}Edge[SIZE_OF_EDGES];
int ECnt;
int Vertex[SIZE_OF_VERTICES];

//Don't forget calling it
//n is the amount of vertices
inline void initGraph(int n){
	ECnt = 2;//ECnt从2开始,空指针用0表示,反向边用^1计算
	fill(Vertex,Vertex+n+1,0);
}

//to build bi-directional edge
inline void mkEdge(int a,int b,weight_t w){
	Edge[ECnt].from = a;
	Edge[ECnt].to = b;
	Edge[ECnt].weight = w;
	Edge[ECnt].next = Vertex[a];
	Vertex[a] = ECnt ++;

	Edge[ECnt].from = b;
	Edge[ECnt].to = a;
	Edge[ECnt].weight = 0;//反向边的容量为0
	Edge[ECnt].next = Vertex[b];
	Vertex[b] = ECnt ++;
}

int L[SIZE_OF_VERTICES];//层次图
int Queue[SIZE_OF_VERTICES];//队列
//建立残留网络从源s到汇t的层次图,n为顶点总数
bool bfs(int s,int t,int n){
	fill(L+1,L+n+1,-1);

	int u,v,head,tail = 0;
	L[Queue[tail++] = s] = 0;

	for(head=0;head<tail;++head){
		//寻找还有残量的边
		for(int p=Vertex[u = Queue[head]];p;p=Edge[p].next){
            //如果有残量又没有被搜索过的,则标记层次
			if ( Edge[p].weight > 0 && -1 == L[v = Edge[p].to] ){
                L[Queue[tail++]=v] = L[u] + 1;
			}			
		}
	}

	return -1 != L[t];
}

//在层次图上搜索增广路径,本质上就是搜索可以增广的流量
//这个流量是各层之间流量的最小值
//u为当前节点,cf为已经搜索出的结果,t为汇点
weight_t dfs(int u,weight_t cf,int t){
	if ( u == t ) return cf;

	weight_t tf = 0;//tf记录u往下一层的总可行流量
	for(int p=Vertex[u];p;p=Edge[p].next){
		int v = Edge[p].to;
		weight_t c = Edge[p].weight;

		if ( L[u] + 1 == L[v] && c > 0 && cf > tf ){
			weight_t f = dfs(v,min(c,cf-tf),t);
			if ( 0 == f ) continue;

			Edge[p].weight -= f;//正向边减去可行流量
			Edge[p^1].weight += f;//反向边加上
			tf += f;
		}
	}
	if ( 0 == tf ) L[u] = -1;//修改层次图
	return tf;
}

//Dinic算法,s为源,t为汇,n为图顶点总数
weight_t Dinic(int s,int t,int n){
	weight_t ret = 0;
	while( bfs(s,t,n) ){//第一步建立分层图
		weight_t ans;
		//第二步在分层图上查找一条增广路径的可行流量
		while( ans = dfs(s,INT_MAX,t) )
			ret += ans;
	}
	return ret;
}

int N,M,S,T;
bool read(){
	if ( EOF == scanf("%d%d",&N,&M) ) return false;
	
	initGraph( T = ( S = N + N + 1 ) + 1 );
	for(int i=1;i<=N;i+=3) mkEdge(i,i+N,1);
	
	int a,b;
	for(int i=0;i<M;++i){
		scanf("%d%d",&a,&b);
		int aa = a % 3;
		int bb = b % 3;
		if ( aa == bb || ( 1 != aa && 1 != bb ) ) continue;
		
		if ( 1 == aa ){
			if ( 2 == bb ) {
				mkEdge(b,a,1);
				mkEdge(S,b,N);
			}else{
				mkEdge(a+N,b,1);
				mkEdge(b,T,N);
			} 
		}else{
			if ( 2 == aa ){
				mkEdge(a,b,1);
				mkEdge(S,a,N);
			}else{
				mkEdge(b+N,a,1);
				mkEdge(a,T,N);
			} 
		} 		
	}
	
	return true;
}
int main(){
	while( read() ){
		printf("%d\n",Dinic(S,T,T));
	}
}




八、神也糊涂

题目连接

  • 来自左神的题解,啊哈哈哈哈哈
#include <bits/stdc++.h>
using namespace std;
/*struct stt{
	int x,y;
};
bool cmp(stt a,stt b)
{
	if (a.x< b.x) 	  		 return 1;
	if (a.x==b.x && a.y<b.y) return 1;
							 return 0;
}
*/
long long n,m;
long long a[1000010],ans[1000010];
int main()
{
	a[1]=1,a[2]=1,a[3]=2,a[4]=9;
	for (int i=5; i<=10020; i+=1)
	{
		long long ls=1;
		for (long long j=i-1; j>=1; j-=1)
		{
			ls*=j;
			ls%=2017;
			a[i]+=ls*a[j-1];
			a[i]%=2017;
		}
	}
	for (int i=2; i<=10020; i+=1)
		ans[i]=a[i];
	
	while(~scanf("%lld",&n))
		printf("%lld\n",ans[n/3]*ans[n/3]*ans[n/3]%2017);
	return 0;
} 




九、神的小学数学题

题目连接

  • 考一丢丢数学知识啦,判断两个三角形是否全等,我们只需要将他们的边的等比算出来,判断是否相等即可拉!
#include <bits/stdc++.h>
using namespace std;
double p[5],q[5];
int main()
{
	int a,b,c,d,e,f,a1,b1,c1,d1,e1,f1;
	while (~scanf("%d%d%d%d%d%d%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f,&a1,&b1,&c1,&d1,&e1,&f1)){
		int pd=0;
		memset(p,0,sizeof p);
		memset(q,0,sizeof q);
		p[1]=sqrt((a-c)*(a-c)+(b-d)*(b-d));
		p[2]=sqrt((a-e)*(a-e)+(b-f)*(b-f));
		p[3]=sqrt((e-c)*(e-c)+(f-d)*(f-d));
		q[1]=sqrt((a1-c1)*(a1-c1)+(b1-d1)*(b1-d1));
		q[2]=sqrt((a1-e1)*(a1-e1)+(b1-f1)*(b1-f1));
		q[3]=sqrt((e1-c1)*(e1-c1)+(f1-d1)*(f1-d1));
		sort(p+1,p+4);
		sort(q+1,q+4);
		for (int i=1;i<=3;i++)
		if (p[i]!=q[i]){
			pd=1;
			break;
		}
		if (pd==0) cout<<"YES";
		else cout<<"NO";
		cout<<endl;
	}
}




十、神的初中数学题

题目连接

#include<bits/stdc++.h>
using namespace std;

int A[100010],B[500010],C[500010];

int f(int a[]){
    int n = rand() % 1001;
	for(int i=0;i<=n;++i) a[i] = rand() % 101;
	while( 0 == a[n] ) a[n] = rand() % 101;
	return n;	
}

int mul(int a[],int an,int b[],int bn,int c[]){
	int cn = an + bn;
	fill(c,c+cn+1,0);
	
	for(int i=0;i<=an;++i)for(int j=0;j<=bn;++j){
		c[i+j] += a[i] * b[j];
	}
	
	return cn;
}

//n表示最高次数,个数为n+1 
void output(int a[],int n,ostream&os){
	os<<a[0];
	for(int i=1;i<=n;++i)os<<" "<<a[i];
	os<<endl;
}

int main(){

    //常数项
	in<<4<<endl<<100<<endl;
	out<<400<<endl;
	
	//零
	in<<0<<endl;
	in<<"2 3 4 1 3 4 5 6 8 5 4 3 9 2 3 4 6"<<endl;
	out<<0<<endl; 
	
	//随机
	for(int i=0;i<98;++i){
		int an = f(A);
		int bn = f(B);
		
		output(A,an,in);
		output(B,bn,in);
		
		int cn = mul(A,an,B,bn,C);
		output(C,cn,out);
	} 
	
	return 0;
}





十一、神的高中数学题

题目连接

  • emmm,有一说一,这次出题是真难
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<double,double>pii;
const double eps=1e-6;
int sign(double x)
{
    if (fabs(x) < eps) return 0;
    if (x < 0) return -1;
    return 1;
}
int cmp(double x, double y)
{
    if (fabs(x - y) < eps) return 0;
    if (x < y) return -1;
    return 1;
}
pii operator -(pii a,pii b)
{
    return {a.x-b.x,a.y-b.y};
}
double cross(pii a,pii b)
{
    return a.x*b.y-a.y*b.x;
}
double dot(pii a, pii b)
{
    return a.x*a.x+b.y*b.y;
}

double multi(pii a,pii b,pii c)
{
    return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
bool isintersected(pii a,pii b,pii c,pii d)
{
    double u,v,w,z;
    u=multi(a,b,c);
    v=multi(a,b,d);
    w=multi(c,d,b);
    z=multi(c,d,a);
    return (u*v<=0.00000001&&w*z<=0.00000001);
}
bool on(pii p, pii a, pii b)
{
    return sign(cross(p - a, p - b)) == 0 && sign(dot(p - a, p - b)) <= 0;
}

double operator *(pii a,pii b)
{
    return a.x*b.y-b.x*a.y; 
}
bool in(pii a,pii b,pii c)
{
    if(fabs((a-b)*(a-c))<eps)
    {
        if(min(b.x,c.x)-eps<=a.x&&a.x-eps<=max(b.x,c.x))
        {
            if(min(b.y,c.y)-eps<=a.y&&a.y-eps<=max(b.y,c.y))
            {
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    pii a,b,c,d;
    while(cin>>a.x>>a.y>>b.x>>b.y>>c.x>>c.y>>d.x>>d.y)
    {
        double k1=(b.y-a.y)/(a.x-b.x);
        double k2=(d.y-c.y)/(c.x-d.x);
        k1=fabs(k1),k2=fabs(k2);
        if((a.x==c.x&&a.y==c.y)&&(b.x!=d.x||b.y!=d.y))cout<<"Y"<<endl;
        else if((a.x==d.x&&a.y==d.y)&&(b.x!=c.x||b.y!=c.y))cout<<"Y"<<endl;
        else if((b.x==c.x&&b.y==c.y)&&(a.x!=d.x||a.y!=d.y))cout<<"Y"<<endl;
        else if((b.x==d.x&&b.y==d.y)&&(a.x!=c.x||a.y!=c.y))cout<<"Y"<<endl;
        else if(cmp(k1,k2)||(k1==0&&k2==0))
        {
            if(in(a,c,d))cout<<"N"<<endl;
            else if(in(b,c,d))cout<<"N"<<endl;
            else if(in(c,a,b))cout<<"N"<<endl;
            else if(in(d,a,b))cout<<"N"<<endl;
            else cout<<"Y"<<endl;
        }
        else if(isintersected(a,b,c,d))cout<<"N"<<endl;
        else cout<<"Y"<<endl;
    }
    return 0;
}

十二、数数码

题目连接

#include <stdio.h>
#include<math.h>
int main() {
	int i,j,k;
	int n = 0;   //页码数
 
	scanf("%d",&n);
 
	int temp,len;   //temp为页码数n临时量,len为页码数长度
	int higher,rest; //页码数高位和其余位
	int count[10] = {0};  //每个数字可用次数
	temp = n;
	len = log10(n);  //求页码位数
 
	//算出0~9每个数字所用的次数
	for(i = 0;i <= len;i ++){
		higher = temp / pow(10,len - i); //高位
		rest = temp % (int)pow(10,len - i);//取余,取除了高位剩余的部分
		count[higher] = count[higher] + rest + 1;//先算出最高位的数所用到的次数,例n=745时高位就是7
 
		for(j = 0;j < higher;j ++){
			count[j] = count[j] + pow(10,len - i);//0~6所用到的次数
 
			for(k = 0;k < 10;k ++){
				count[k] = count[k] + (len - i) * pow(10,len - i - 1);//00~99所用到的次数
			}
		}
 
		temp = rest;
	}
	//去掉多余的0
	for(i = 0;i <= len;i ++){
		count[0] = count[0] - pow(10,len - i);
	}
 
	for(i = 0;i < 10;i ++){
		printf("%d\n",count[i]);
	}
 
	return 0;
}

总结:

  • 首先呢,这次出题确实是有难度的,自己来做的话也只能写个五六道的样子。emmm
  • 咳咳,出题也是比较急,因为只有一天的时候准备,只有一个人,嘤嘤嘤
  • 但是呢,相比起以后的各大赛事的罚坐,我们感觉先来体验一下也不是不行,啊哈哈哈哈哈
  • 也是给大一的学弟学妹们提一个醒,加油吧,未来是你们的。。。
  • 别骂了别骂了。。。嘤嘤嘤
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木不会

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值