(JZOJ)2021年3月13日比赛总结

(JZOJ)2021年3月13日比赛总结

开头:

今天的考试针不戳,我居然超过了刘奆!(刘奆:明明是你那题的数据点少好吗)不过,没有一个人超了200分,有那么一 丶丶惨,不过木有关系,让我们开始今天的总结吧!

T1

​ 环数是那些不包括0这个数字的没有重复数字的整数 (比如说, 81362) 并且同时具有一个有趣的性质, 就像这个例子:

  • 如果你从最左边的数字开始 ( 在这个例子中是8) 数最左边这个数字个数字到右边(回到最左边如果数到了最右边),你会停止在另一个新的数字(如果没有停在一个不同的数字上,这个数就不是循环数). 就像: 8 1 3 6 2 从最左边接下去数8个数字: 1 3 6 2 8 1 3 6 所以下一个数字是6.
  • 重复这样做 (这次从“6”开始数6个数字) 并且你会停止在一个新的数字上: 2 8 1 3 6 2, 也就是2.
  • 再这样做 (这次数两个): 8 1
  • 再一次 (这次一个): 3
  • 又一次: 6 2 8 这是你回到了起点, 在从每一个数字开始数1次之后. 如果你在从每一个数字开始数一次以后没有回到起点, 你的数字不是一个循环数。

给你一个数字 M (在1到9位之间), 找出第一个比 M大的循环数, 并且一定能用一个无符号长整形数装下。

INPUT FORMAT

仅仅一行, 包括M

SAMPLE INPUT (file runround.in)

81361

OUTPUT FORMAT

仅仅一行,包括第一个比M大的循环数。

SAMPLE OUTPUT (file runround.out)

81362

那么这道题,其实直接高精度加暴力就能过,为什么要那么麻烦呢?

直接上代码!

#include<bits/stdc++.h>
using namespace std;
int n;
int a[11],b[11],v[11];
int zhuanhuan(int x)
{
	int sum=0;
	while(x>0)
	{
		b[++sum]=x%10;
		x/=10;
	}
	for(int i=1; i<=sum; ++i)
		a[i]=b[sum-i+1];
	return sum; 
}
bool flag(int x)
{
	int s=1;
	memset(v,0,sizeof(v));
	for(int i=1; i<=x; ++i)
	{
		if(v[a[s]]||a[s]==0) return false;
		v[a[s]]++;
		s=(s+a[s])%x;
		if(s==0) s=x;
	}
	if(s!=1) return false;
	else return true;
}
int main()
{
	cin>>n;
	for(int i=n+1; i<=999999999; i++)
	{
		int u=zhuanhuan(i);
		if(flag(u))
		{
			cout<<i; 
			return 0;
		}
	}
}

就这样,不简简单单就过了吗?

T2

​ 对于从1到N的连续整集合合,能划分成两个子集合,且保证每个集合的数字和是相等的。

举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,他们每个的所有数字和是相等的:

  • {3} and {1,2}

这是唯一一种分发(交换集合位置被认为是同一种划分方案,因此不会增加划分方案总数)

如果N=7,有四种方法能划分集合{1,2,3,4,5,6,7},每一种分发的子集合各数字和是相等的:

  • {1,6,7} and {2,3,4,5} {注 1+6+7=2+3+4+5}
  • {2,5,7} and {1,3,4,6}
  • {3,4,7} and {1,2,5,6}
  • {1,2,4,7} and {3,5,6}

给出N,你的程序应该输出划分方案总数,如果不存在这样的划分方案,则输出0。程序不能预存结果直接输出。

PROGRAM NAME: subset

INPUT FORMAT

输入文件只有一行,且只有一个整数N

SAMPLE INPUT (file subset.in)

7
OUTPUT FORMAT

输出划分方案总数,如果不存在则输出0。

SAMPLE OUTPUT (file subset.out)

4

这道题,怎么说呢。。。

就是两个dp的事情。。。

背包,背包大家都会吧。。。。

#include<bits/stdc++.h>
using namespace std;
long long b[61][6001],a[101];
int main()
{
	int n;
	cin>>n;
	int maxx=0;
	for(int i=1; i<=n; i++)	
	{
		a[i]=i;
		maxx+=a[i];
	}
	if(maxx%2!=0)
	{
		cout<<0;
		return 0;
	}
	b[1][1]=1;b[0][0]=1;
	for(long long i=1; i<=n; i++)
	{
		for(long long j=maxx; j>=0; j--)
		{
			if(a[i]>j)
				b[i][j]=b[i-1][j];
			else
				b[i][j]=b[i-1][j]+b[i-1][j-a[i]];
		}
	}
	cout<<b[n][maxx/2]/2;
	return 0;
}

简单,过!

T3

​ 在IOI98的节日宴会上,我们有N(10<=N<=100)盏彩色灯,他们分别从1到N被标上号码。

这些灯都连接到四个按钮:

  • 按钮1:当按下此按钮,将改变所有的灯:本来亮着的灯就熄灭,本来是关着的灯被点亮。
  • 按钮2:当按下此按钮,将改变所有奇数号的灯。
  • 按钮3:当按下此按钮,将改变所有偶数号的灯。
  • 按钮4:当按下此按钮,将改变所有序号是3*K+1(K>=0)的灯。例如:1,4,7…

一个计数器C记录按钮被按下的次数。

当宴会开始,所有的灯都亮着,此时计数器C为0。

你将得到计数器C(0<=C<=10000)上的数值和经过若干操作后所有灯的状态。写一个程序去找出所有灯最后可能的与所给出信息相符的状态,并且没有重复。

PROGRAM NAME: lamps

INPUT FORMAT

不会有灯会在输入中出现两次。

第一行:N。
第二行:C最后显示的数值。
第三行:最后亮着的灯,用一个空格分开,以-1为结束。
第四行:最后关着的灯,用一个空格分开,以-1为结束。

SAMPLE INPUT (file lamps.in)

10

1

-1

7 -1

在这个样例中,有10盏灯,只有1个按钮被按下。最后7号灯是关着的。

OUTPUT FORMAT

每一行是所有灯可能的最后状态(没有重复)。每一行有N个字符,第1个字符表示1号灯,最后一个字符表示N号灯。0表示关闭,1表示亮着。这些行必须从小到大排列(看作是二进制数)。

如果没有可能的状态,则输出一行’IMPOSSIBLE’。

SAMPLE OUTPUT (file lamps.out)

0000000000

0101010101

0110110110

在这个样例中,有三种可能的状态:

  • 所有灯都关着
  • 1,4,7,10号灯关着,2,3,5,6,8,9亮着。
  • 1,3,5,7,9号灯关着,2, 4, 6, 8, 10亮着。

这道题,偶不会。。。

各位大大教一下呗!

难。。。过!!!

T4

​ 在生物学中,一些生物的结构是用包含其要素的大写字母序列来表示的。生物学家对于把长的序列分解成较短的(称之为元素的)序列很感兴趣。

如果一个集合 P 中的元素可以通过串联(允许重复;串联,相当于 Pascal 中的 “+” 运算符)组成一个序列 S ,那么我们认为序列 S 可以分解为 P 中的元素。并不是所有的元素都必须出现。举个例子,序列 ABABACABAAB可以分解为下面集合中的元素:

	   {A, AB, BA, CA, BBC}

序列 S 的前面 K 个字符称作 S 中长度为 K 的前缀。设计一个程序,输入一个元素集合以及一个大写字母序列,计算这个序列最长的前缀的长度。

PROGRAM NAME: prefix

INPUT FORMAT

输入数据的开头包括 1…200 个元素(长度为 1…10 )组成的集合,用连续的以空格分开的字符串表示。字母全部是大写,数据可能不止一行。元素集合结束的标志是一个只包含一个 “.” 的行。集合中的元素没有重复。接着是大写字母序列 S ,长度为 1…200,000 ,用一行或者多行的字符串来表示,每行不超过 76 个字符。换行符并不是序列 S 的一部分。

SAMPLE INPUT (file prefix.in)

A AB BA CA BBC

ABABACABAABC

OUTPUT FORMAT

只有一行,输出一个整数,表示 S 能够分解成 P 中元素的最长前缀的长度。

SAMPLE OUTPUT (file prefix.out)

11

这道题,是一个较为暴力的DP,直接最长不下降子序列反过来加背包就行了!!

#include<bits/stdc++.h>
using namespace std;
int len[201];
char h[201][11];
int sum=0;
int f[200001];
char y[110];
char s[200001];
int main()
{
	int n=0;
	while(1)
	{
		scanf("%s",h[++n]+1);
		len[n]=strlen(h[n]+1);
		if(len[n]==1&&h[n][1]=='.')
		{
			n--;
			break;
		}
	}
	while(scanf("%s",y)==1)
	{
		strcat(s,y);
	}
	int lens=strlen(s);
	for(int i=lens-1; i>=0; i--)
	{
		for(int j=1; j<=n; j++)
		{
			int k;
			if(i+len[j]>lens) 
				continue;
			for(k=i; k<=i+len[j]-1; k++)
			{
				if(s[k]!=h[j][k-i+1])
				{
					break;
				}
			}
			if(k>=i+len[j])
			{
				f[i]=max(f[i],f[i+len[j]]+len[j]);
			}
			
		}
	}
	cout<<f[0]<<endl;
}
}

今天的考试挺不错,下次加油!!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值