NOIP提高组 模拟赛 Day1

T1 单峰数计数

Description

一个n的全排列A[i]是单峰的,当且仅当存在某个x使得A[1]A[x+1]>...> A[n]。例如,对于9的全排列,125798643是一个单峰排列,123456789也是一个单峰排列,但356298741就不是。试求n的单峰全排列的个数。

Input

输入一个数n。

Output

输出n的全排列中单峰排列的个数。由于这个数可能很大,因此你只需要输出它mod 1234567的值。

Sample Input

3
Sample Output
4

Hint

##### 样例解释
共有以下4种方案:
123
132
231
321
##### 数据规模
对于20%的数据,n<=25。
对于100%的数据,n<=2*10^9。
 
对于100%的数据,显然时间复杂度在O(logn)以下。
所以~手动打表找规律。
当n=1时 只有1种情况:1
当n=2时 有2种情况:12 21
当n=3时 有4种情况:即样例解释
当n=4时 有8种情况:1234 1243 1342 1432 2341 2431 3421 4321
当n=5时 有16种情况:12345 12354 12453 12543 13452 13542 14532 15432 23451 24531 23541 25431 34521 35421 45321 54321
当n=6时 有32种情况,这里不方便举出了。
所以n=k时,有2k-1种情况,快速幂。
实际上,我们可以假设1放中间,后面每个数都可以放在这串数的两边,并且满足单峰。
 1 #include
 2 #define int long long
 3 #define P 1234567
 4 using namespace std;
 5 
 6 int n;
 7 
 8 int qpow(int x,int y)
 9 {
10     int ans=1,b=x;
11     while(y!=0)
12     {
13         if(y&1) ans=ans*b%P;
14         b=b*b%P;
15         y>>=1;
16     }
17     return ans;
18 }
19 signed main(){
20     scanf("%lld",&n);
21     if(n==1)
22     {
23         printf("1");
24         return 0;
25     }
26     printf("%lld",qpow(2,n-1));
27     return 0;
28 }
T1 Code
 
T2 矩阵行走
Description
有一块n *n 的土地上,明明和亮亮站在(1,1)处。每块地上写有一个数字a(i, j)。现在他们决定玩一个游戏,每一秒钟,他们俩走向相邻且坐标变大的格子(从(x,y)到(x+1,y)或者从(x,y)到(x,y+1)),他们俩可以按照不同方式来走,最后经过2n-1步到达(n,n)处。明明和亮亮每一秒钟计算他们站的两个位置上数字的差的绝对值,他们希望这些差值的和最大,请问这个最大的和是多少? Input 第一行一个正整数n。后面n行,每行n个整数,分别表示每块地上的数字。 Output 一个整数,表示最大的差值的和。 
Sample Input
4
1 2 3 4
1 5 3 2
8 1 3 4
3 2 1 5
Sample Output
13
Hint
【数据规模】对于20%的数据,n<=10。对于100%的数据,n <= 100, 每块地上的数字的绝对值不超过300。
 
典型动态规划。
定义f[i][j][k]表示走到第i步时,一个人站在横坐标为j的格子上,另一个人站在横坐标为i的格子上,当前答案(差值)的最大值。
那么第一个人的位置为(j,i-j+1),第二个人的位置是(k,i-k+1)。
f[i][j][k]=max(max(f[i-1][j][k-1],f[i-1][j-1][k]),max(f[i-1][j-1][k-1],f[i-1][j][k]))+abs(a[j][i-j+1],a[k][i-k+1])
时间复杂度O(n3)
 
 
T3 数字转换
Description
如果一个数x的约数和(不包括它本身,下同)比它本身小,那么x可以变成它的约数和;如果对于某个y>x且y的约数和为x,那么x也可以变成y。例如,4可以变为3,1可以变为7。限定所有的数字变换在不超过n的正整数范围内进行,求不断进行数字变换且没有重复数字出现的最多变换步数。 Input 输入一个正整数n。 Output 输出最少需要花费的时间。 
Sample Input
7
Sample Output
3
Hint
【样例解释】一种方案为:4→3→1→7。
【数据规模】对于10%的数据,n<10。对于30%的数据,n<100。对于100%的数据,n<=50000。
 
可以用树形Dp做
首先,要找每个数的约数和。
其次,在一个数和他的约数和之间建一条边,边长为1。
显然,这就是典型的最长链问题了。
在每个点记录当前的第一长链f1和第二长链f2,最后f1+f2就是经过该点的最长链。
 1 #include
 2 #define MAXN 50009
 3 using namespace std;
 4 
 5 int f1[MAXN],f2[MAXN],sum[MAXN],n;
 6 int main(){
 7     scanf("%d",&n);
 8     for(int i=1;i)
 9         for(int t=(i<<1);t<=n;t+=i) sum[t]+=i;
10     for(int i=n;i>0;i--)
11     {
12         int t=sum[i];
13         if(t>=i) continue;
14         if(f1[i]+1>f1[t]) f2[t]=f1[t],f1[t]=f1[i]+1;
15         else if(f1[i]+1>f2[t]) f2[t]=f1[i]+1;
16     }
17     int ans=-1;
18     for(int i=1;i<=n;i++) ans=max(ans,f1[i]+f2[i]);
19     printf("%d",ans);
20     return 0;
21 } 
T3 Code

你可能感兴趣的:(NOIP提高组 模拟赛 Day1)