(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;
}
}
今天的考试挺不错,下次加油!!!!