2017暑假第二阶段第八场 总结
2017-08-29 19:54
232 查看
T1 回文数
问题描述给你一个数N,求出最小的B(B>=2),使得 N在 B进制下为回文数。
输入格式
第一行1个整数TEST,表示数据组数。 接下来TEST行,每行一个整数N。
输出格式
共输出TEST行,每行对应一个答案B
数据范围
30%的数据 TEST<=10,N<=104。
100%的数据 TEST<=1,000,N<=1010。
比较常见的思路是把原数写成ak−1Bk−1+ak−2Bk−2+……+a1B1+a0B0的形式,然后就做不起了,只能暴力转进制搞了。
不妨换一种考虑的方向。考虑原数转换为B进制之后的位数,从而优雅地暴力。
首先转换后只有一位数肯定不是最优解,因为这样的话B满足B>N,然而在B=N-1时,一定是两位的回文数(11)N−1(对于数字2除外,因为并没有一进制)。
如果转换后是两位数,那么一定是(AA)B的形式,那么满足N=A×B+A=A(B+1),那么从大到小枚举因数A即可。
如果转换后是三位数,那么最小也是(101)B,所以有N≥B2+1,根据N的范围,B<
14950
/nobr>最大仅为105,大于三位数之后B的范围肯定更小,在这个数据范围暴力枚举是可以接受的。
于是得出解法:首先在N−−√以内暴力寻找是否有这样的B;如果找到就停止,如果没找到就枚举N的因数。但是要注意,这样的因数必须要大于N−−√才是符合要求的,因为N−−√以内的B已被枚举过,且被验证为不满足要求。
#include<stdio.h> #include<cmath> #define ll long long using namespace std; ll N; int a[65]; bool check(int b) { if(!N)return true; int cnt=0,i; ll tmp=N; while(tmp) { a[++cnt]=tmp%b; tmp/=b; } for(i=1;i<=cnt-i+1;i++)if(a[i]!=a[cnt-i+1])return false; return true; } int main() { int T; ll i,tmp; bool flag; scanf("%d",&T); while(T--) { flag=false; scanf("%lld",&N); if(N==2){puts("3");continue;} tmp=ceil(sqrt(N)); for(i=2;i<=tmp;i++) { if(check(i)) { flag=true; printf("%lld\n",i); break; } } if(flag)continue; for(i=tmp-1;i>=1;i--) { if(N%i==0&&(N/i-1)>tmp) { printf("%lld\n",N/i-1); break; } } } }
T2 奶牛阵列
问题描述每天早晨约翰的奶牛都会在挤奶的时候排成阵列,即站成R(1<=R<=10000)行C(1<=C<=75)列的矩阵。我们知道,约翰是奶牛专家,他打算写一本关于喂养奶牛的书,他发现,当奶牛按不同血统标记以后,整个大矩阵就像由很多小矩阵无缝拼接的一样。
请帮助约翰找到面积最小的模型矩阵,使他能拼出整个大矩阵,当然,模型矩阵的尺寸不一定能整除大矩阵,也就是说你可以用若干个模型矩阵,拼出一个包含大矩阵的更大的矩阵。
输入格式
第一行, 两个整数R和C
接下来是由大写字母构成的R*C的矩阵
输出格式
一个整数,表示最小模型矩阵的面积。
样例输入
2 5
ABABA
BABAB
样例输出
4
样例说明:
模型矩阵如下:
AB
BA
拼出的大矩阵如下:
ABABAB
BABABA
根据题意,应该是不能把小矩形重叠放置的。但是由于本题数据太弱,很多错解都能AC。对于错解,这里不一一列举,正解是KMP。
不妨先把每一列考虑成一个字符,再对这些“字符”通过KMP找出“最小循环节”,即最小循环矩形,并记录长度;再把每一行也考虑成一个字符,并进行相同的操作。那么答案就是两个“长度”的乘积。KMP找最小循环矩形的正确性是显然的,求答案的操作可以通过下面的图理解:
将字符串转换为“字符”考虑后,我们仅关心两个“字符”是否相同,那么可以使用hash。如果害怕hash出错,也可以开两个hash表。但是由于数据本身太弱,这里就只开了一个。
#include<stdio.h> #define ll long long #define mod 0xffff int R,C,fail[10005],rans,cans; ll Hash[10005]; char ch[10005][80]; int main() { int i,j,sd=131; ll h; scanf("%d%d",&R,&C); for(i=1;i<=R;i++)scanf("%s",&ch[i][1]); for(i=1;i<=R;i++) { h=0; for(j=1;j<=C;j++)h=(h+ch[i][j])*sd%mod; Hash[i]=h; } fail[1]=j=0; for(i=2;i<=R;i++) { while(j>0&&Hash[j+1]!=Hash[i])j=fail[j]; if(Hash[j+1]==Hash[i])j++; fail[i]=j; } rans=R-fail[R]; for(i=1;i<=C;i++) { h=0; for(j=1;j<=R;j++)h=(h+ch[j][i])*sd%mod; Hash[i]=h; } fail[1]=j=0; for(i=2;i<=C;i++) { while(j>0&&Hash[j+1]!=Hash[i])j=fail[j]; if(Hash[j+1]==Hash[i])j++; fail[i]=j; } cans=C-fail[C]; printf("%d",cans*rans); }
提供几组肉眼就能看出答案的小数据,能够卡掉很多AC代码。
/* data1: 3 9 CBABCCBBC CACBAACCA BACCCAABB 正解27 data2: 2 6 BACBAC CBCBAC 正解12 data3: 5 7 BAAAABB ABABABA ABABAAB BAAAAAA BBABABB 正解35 data4: 2 8 AAABCAAA ABABABAB 正解12 */
T3 突击队
问题描述何老板的公司有t名员工,编号1到t.
何老板将他们分成了n组,每组员工的编号都是连续的,比如第i组[Ai,Bi]表示编号Ai,Ai+1,…,Bi都属于该组。
现何老板接到一个大单,工期很紧,需要组成一个突击组来完成任务,他想在每个组里抽出一些员工来组成突击组。现在告诉你每个组至少要抽出的人数,问,该突击组的人数最少是多少?
输入格式
第一行,一个整数n
接下来n行,每行三个整数Ai,Bi,Ci,描述一个组的情况,其中Ai,Bi表示该组员工编号的范围,Ci表示改组中至少要抽出Ci个人去突击组。
输出格式
一个整数,表示所求的答案。
数据范围
0 <= t <= 50000
1 <= n <= 50000
ai <= bi
1 <= ci <= bi - ai+1
方向对了就是道水题,如果不对什么错解都能想出来。
正解是差分约束。所有的区间的数据都可以看成前缀和相减的一个不等式。由于一个编号的人一定有一个,不会存在负数个人(废话),此外的约束条件还有:0≤sumi−sumi−1≤1。
一开始还想写个Dijkstra+Heap,结果忘了Dijkstra不能处理负权边……
#include<stdio.h> #include<queue> #include<cstring> #define Max(x,y) ((x>y)?(x):(y)) #define MAXN 50005 #define MAXM 150005 using namespace std; int N,T; int en[MAXM],nex[MAXM],las[MAXN],len[MAXM],tot; void ADD(int x,int y,int z) { en[++tot]=y; nex[tot]=las[x]; las[x]=tot; len[tot]=z; } int dis[MAXN]; bool mark[MAXN]; void SPFA(int s) { int i,x,y; memset(dis,-60,sizeof(dis)); queue<int>Q; Q.push(s); dis[s]=0; while(Q.size()) { x=Q.front();Q.pop();mark[x]=false; for(i=las[x];i;i=nex[i]) { y=en[i]; if(dis[y]<dis[x]+len[i]) { dis[y]=dis[x]+len[i]; if(!mark[y])mark[y]=true,Q.push(y); } } } } int main() { int i,x,y,z; scanf("%d",&N); for(i=1;i<=N;i++) { scanf("%d%d%d",&x,&y,&z); ADD(x-1,y,z); T=Max(T,y); } for(i=1;i<=T;i++) { ADD(i,i-1,-1); ADD(i-1,i,0); } SPFA(0); printf("%d",dis[T]); }
总结
这次考试又很爆炸,只不过收获很大,至少暴露了很多知识点的不熟悉。T1打表找规律太久,结果发现压根就没有规律,要学会更优雅的暴力解法,思考问题的角度也要多样化,不能江化;T2正解思考的方式也很值得借鉴,KMP算法还要加强;T3主要是提醒了差分约束这种算法,太久没有用了,确实错得应该。
相关文章推荐
- 2017暑假第二阶段第七场 总结
- 2017暑假第二阶段第四场 总结
- 2017暑假第二阶段第三场 总结
- 2017暑假第二阶段第五场 总结
- 2017暑假第二阶段第一场 总结
- 2017暑假第二阶段第九场 总结
- 第二冲刺阶段 工作总结 01
- 《校园封神榜》第二阶段个人工作总结——第三天
- 第二阶段第九天站立会议总结
- 王彪20162321 2017-2018程序设计与数据结构-第二学期-第一周学习总结
- 第二阶段团队冲刺个人工作总结三
- 冲刺第二阶段工作总结01
- 第二阶段冲刺——个人总结01
- 大暑假集训 第一阶段总结 233
- 冲刺第二阶段工作总结02
- 暑假集训第三周第二阶段搜索 H - Zipper
- 第二阶段个人博客总结4
- 第二阶段个人工作总结(3)
- 个人工作总结07(第二阶段)
- 第二冲刺阶段——个人工作总结07