校内集训10.30小结

编程入门 行业动态 更新时间:2024-10-08 08:33:40

<a href=https://www.elefans.com/category/jswz/34/1766800.html style=校内集训10.30小结"/>

校内集训10.30小结

校内集训10.30小结

  • T1:繁繁的数字
  • T2:繁繁的游戏
  • T3:繁繁的队列

前言:这次考试我当场翻车,现场十分惨烈,为了避免同样的悲剧再次上演,我决定写一篇总结。

T1:繁繁的数字

题目描述
繁繁今天学习了二进制,繁繁觉得二进制很神奇,任何一个整数都可以由一些互不相同的2的方幂
表示,例如7的二进制是 ,所以7=4+2+1,繁繁不满足于此,繁繁在想,如果把互不相同这
个条件去掉,会有多少种方案呢?

输入
一行一个整数N(1<=N<=1000000)

输出
一个一个数,表示答案对1000000007取模的结果

输入样例1

7

输入样例2

8

输入样例3

9

输出样例1

6

输出样例2

10

输出样例3

10

提示
样例解释
对于样例1,7=4+2+1=4+1+1+1=2+2+2+1=2+2+1+1+1=2+1+1+1+1+1=1+1+1+1+1+1+1,6种
方案。
对于30%的数据,N<=300
对于50%的数据,N<=10000
对于100%的数据,1<=N<=1000000

简要思路:这题直接推导一个通项公式好像有点困难,不过,我们可以考虑一个数(例如上面的7),设 c n t ( 7 ) cnt(7) cnt(7)为对答案7的统计,从大到小拆除7,我们可以枚举7第一个拆出的数。
如果拆出4,可继续往后统计3拆分但不会拆出比4大的数的个数(3=2+1=1+1+1);
如果拆出2,可继续往后统计5拆分但不会拆出比2大的数的个数(5=2+2+1=2+1+1+1=1+1+1+1+1);
如果拆出1,可继续往后统计6拆分但不会拆出比1大的数的个数(6=1+1+1+1+1+1)。
从这可以看出,答案的统计似乎需要有限制的统计方法,头绪不够明晰,似乎只能用计搜,但是,通过仔细观察,我们不难发现拆出的数不能比 2 x 2^x 2x大这一条件好像可以用背包问题来解决,将 2 x 2^x 2x放到外层当做物品循环即可。并且会出现拆出若干同样的数的情况,这就是完全背包了。时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define mod 1000000007
using namespace std;
int er[21];
int cnt[1000005];
int n;
template < typename T >
inline void read( T & res ) {res = 0;T pd = 1;char aa = getchar();while ( aa < '0' || aa > '9' ) {if ( aa == '-' ) {pd = -pd;}aa = getchar();}while ( aa >= '0' && aa <= '9' ) {res = ( res << 1 ) + ( res << 3 ) + ( aa - '0' );aa = getchar();}res *= pd;return;
}
int main () {read(n);er[0] = 1;for ( int i = 1 ; i <= 20 ; ++i ) {er[i] = er[i - 1] * 2;}memset( cnt , 0 , sizeof(cnt) );cnt[0] = 1;for ( int j = 0 ; j <= 20 ; ++j ) {for ( int i = er[j] ; i <= n ; ++i ) {cnt[i] = ( cnt[i] + cnt[i - er[j]] ) % mod;}}printf("%d",cnt[n]);return 0;
}

T2:繁繁的游戏

题目描述
繁繁想和小伙伴们打游戏,游戏在一个山庄进行,这个山庄有N座山,编号为1到N,为了方便大
家在不同的山之间移动,繁繁建了一些桥,由于技术的原因,桥连接的两座山的高度差不能超过
d,现在已知这些桥,求这个山庄最高的山和最低的山差距最大是多少?数据保证所有山之间都是
联通的。

输入
第一个一个数T,表示测试数据数量(T<=5,2<=N<=50,0<=d<=1000)
每组数据第一行两个数N和d
接下来一个N行N列的矩阵,第i行j列为Y表示i和j之间建了一座桥,否则表示没有建
保证第i行j列和第j行i列值相同,并且第i行第i列值为N

输出
T行,每行一个答案,若最大值可能为正无穷,输出-1

样例输入

3
3 10
NYN
YNY
NYN
2 1
NN
NN
6 1000
NNYNNN
NNYNNN
YYNYNN
NNYNYY
NNNYNN
NNNYNN

样例输出

20
-1
3000

提示
样例解释
第一个样例,1和2之间不能超过d,2和3之间不能超过d,那么最大就是1和2差恰好为d,2和3差
恰好为d
第二个样例,1和2之间没有限制,那么他们之间可能差为正无穷
对于20%的数据,T<=3,N<=40
对于50%的数据,T<=3
对于100%的数据,T<=5,2<=N<=50,0<=d<=1000

简要思路:不难看出,在没有环时,答案就是最长的两点最短路*d。
遇到环时,答案也是一样的。

如上图,当一个点经过环到达另一个点时,增加的值为环上的最短路,剩下的长路就随便了,只要符合题意就行。对于环上的两点同理。
本题就是求最大的两点之间最短路,用floyrd算法最方便,时间复杂度为 O ( n 3 ) O(n^3) O(n3)。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define N 55
#define M 5005
using namespace std;
char s[N];
int dis[N][N];
int maxn , n , t , d;
template < typename T >
inline void read( T & res ) {res = 0;T pd = 1;char aa = getchar();while ( aa < '0' || aa > '9' ) {if ( aa == '-' ) {pd = -pd;}aa = getchar();}while ( aa >= '0' && aa <= '9' ) {res = ( res << 1 ) + ( res << 3 ) + ( aa - '0' );aa = getchar();}res *= pd;return;
}
int main () {read(t);while ( t-- ) {maxn = 0;memset( dis , 0x3f , sizeof(dis) );read(n);read(d);for ( int i = 1 ; i <= n ; ++i ) {dis[i][i] = 0;scanf("%s",s);for ( int j = i + 1 ; j <= n ; ++j ) {if ( s[j - 1] == 'Y' ) {dis[i][j] = dis[j][i] = 1;}}}for ( int k = 1 ; k <= n ; ++k ) {for ( int i = 1 ; i <= n ; ++i ) {for ( int j = 1 ; j <= n ; ++j ) {dis[j][i] = dis[i][j] = min( dis[i][j] , dis[i][k] + dis[k][j] );}}}for ( int i = 1 ; i <= n ; ++i ) {for ( int j = i + 1 ; j <= n ; ++j ) {maxn = max( maxn , dis[i][j] );}}if ( maxn == 0x3f3f3f3f ) {printf("-1\n");} else {printf("%d\n",maxn * d);}}return 0;
}

T3:繁繁的队列

题目描述
繁繁有一个双向队列,队列里有数字1-N这N个数字,繁繁每次可以从队列中任意拿出一个数字,
将其放在队列的头部或者队列的尾部,不停这样操作,直到队列变成升序,求最小操作次数。

输入
第一行一个数字N(N<=50000)
接下来N行,每行一个数字

输出
一个数表示最小操作次数

输入样例1

5
2
5
3
4
1

输入样例2

4
3
2
1
4

输入样例3

5
4
2
1
3
5

输出样例1

2

输出样例2

2

输出样例3

3

提示
样例解释
对于样例1,5个数:2,5,3,4,1
step1:5放到队尾→2,3,4,1,5;
step2:1放到队头→1,2,3,4,5;
需要两步操作。
对于30%的数据,N<=100
对于50%的数据,N<=1000
对于100%的数据,N<=50000

简要思路:这题可以换一种思维方式,将一些数按顺序放在开头,另一些数放在末尾,剩下的数就是在原来的数列中也保持1到n的顺序的数。只要找到最大的满足该性质的子序列即可。我们要找的正是“最大数值连续位置可以不连续的单调递增子序列”,方法请参考代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#define N 50005
using namespace std;
int num[N] , pos[N] , flag[N];
int n , k;
template < typename T >
inline void read( T & res ) {res = 0;T pd = 1;char aa = getchar();while ( aa < '0' && aa < '9' ) {if ( aa == '-' ) {pd = -pd;}aa = getchar();}while ( aa >= '0' && aa <= '9' ) {res = ( res << 1 ) + ( res << 3 ) + ( aa - '0' );aa = getchar();}res *= pd;return;
}
int main () {read(n);for ( int i = 1 ; i <= n ; ++i ) {read(k);pos[k] = i;}for ( int i = 1 ; i <= n ; ++i ) {if ( pos[i] < pos[i + 1] ) {flag[i] = 1;}}k = 0;int tot = 1;for ( int i = 1 ; i <= n ; ++i ) {if ( flag[i] ) {tot++;} else {tot = 1;}if ( tot > k ) {k = tot;}}printf("%d",n - k);return 0;
}

这次连简单题都翻车了,以后还是要多注意啊,切忌把简单题复杂化

更多推荐

校内集训10.30小结

本文发布于:2024-02-27 22:51:59,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1766762.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:校内   小结

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!