出给学弟的普及模拟赛,现在题解搬到这里来,估计也没人看了,坟贴一个。
T1 函数(function)
题意
给定两个自变量是 x x x 因变量是 y y y 的函数,这两个函数有可能为二次函数、一次函数或常函数。求两个函数图像交点个数。
对于 100 % 100\% 1 0 0 % 的数据,保证两个函数中每项的系数的绝对值不超过 100 100 1 0 0 。
算法一
基础题,注意判断为直线或者抛物线,再注意一下交点有无数个的情况,期望得分 100 100 1 0 0 分。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <stdio.h> using namespace std;int a,b,c,a1,b1,c1,D;int main () { freopen ("function.in" ,"r" ,stdin),freopen ("function.out" ,"w" ,stdout); scanf ("%d%d%d%d%d%d" ,&a,&b,&c,&a1,&b1,&c1),a-=a1,b-=b1,c-=c1; if (a==0 ) { if (b==0 ) { if (c==0 ) printf ("W" ); else printf ("0" ); } else printf ("1" ); } else { D=b*b-4 *a*c; if (D<0 ) printf ("0" ); if (D==0 ) printf ("1" ); if (D>0 ) printf ("2" ); } return 0 ; }
T2 麻将(majiang)
题意
有一种新型的麻将,这麻将没有饼条万这样的花色,只有一种花色,也没有字牌;序数也不限于 1 1 1 到 9 9 9 ,而是在 1 1 1 到 n n n 的范围内。
关于新型麻将的概念:
胡牌 :即完成的牌,由 3 m + 2 3m+2 3 m + 2 张牌组成,其中有一个对子(两张一样的牌)和 m m m 个顺子(三张序数相连的序数牌,如 234 234 2 3 4 、 678 678 6 7 8 )或刻子(三张一样的牌)。
听牌 :一组听牌的牌是指一组 3 m + 1 3m+1 3 m + 1 张牌,且再加上某一张牌就可以组成胡牌。那一张加上的牌可以称为等待牌。
判断一副牌是不是听牌,若是,找出所有的等待牌。
对于 70 % 70\% 7 0 % 的数据,n ≤ 200 , m ≤ 800 n \le 200,m \le 800 n ≤ 2 0 0 , m ≤ 8 0 0 。
对于 100 % 100\% 1 0 0 % 的数据,9 ≤ n ≤ 400 , 4 ≤ m ≤ 1000 9≤n≤400,4≤m≤1000 9 ≤ n ≤ 4 0 0 , 4 ≤ m ≤ 1 0 0 0 。
算法一
用深搜来寻找答案,我们先枚举每一张听牌,那么很显然,时间复杂度就是 O ( n ) O(n) O ( n ) , 再用深搜来判断可否胡牌。
我们用 c n t x cnt_x c n t x 来表示数值为 x x x 的牌出现了多少次。那么我们就从 1 1 1 到 n n n 枚举对子,再枚举刻子和顺子。那么深搜的时间复杂度是 O ( 2 n 2 ) O(2n^2) O ( 2 n 2 ) ,合起来就是 O( 2 n 3 ) (2n^3) ( 2 n 3 ) ,空间复杂度为 O ( n ) O(n) O ( n ) ,期望得分 70 70 7 0 分。
算法二
先枚举对子。
这是为何?两个原因:
先凑出对子,听的牌如果是顺子就可能有两张听牌。
确定对子容易确定自己的顺子或刻子要怎么拼凑。
枚举对子后,因为剩下的都是三张三张的,就容易枚举了,直接考虑刻子和顺子的两种情况即可。时间复杂度为 O ( n 3 ) O(n^3) O ( n 3 ) ,空间复杂度为 O ( n ) O(n) O ( n ) ,期望得分 100 100 1 0 0 分。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <stdio.h> #define il inline using namespace std;const int N=4005 ;int n,m,tuc[N],tuf[N];il int check () { int i,j,o; for (i=1 ; i<=n; i++) if (tuc[i]>=2 ) { for (j=o=1 ,tuc[i]-=2 ; j<=n+2 ; j++) tuf[j]=tuc[j]; for (j=1 ; j<=n+2 ; j++) { if (tuf[j]<0 ){o=0 ;break ;} tuf[j]%=3 ,tuf[j+1 ]-=tuf[j],tuf[j+2 ]-=tuf[j]; } tuc[i]+=2 ; if (o) return 1 ; } return 0 ; } int main () { freopen ("majiang.in" ,"r" ,stdin),freopen ("majiang.out" ,"w" ,stdout); scanf ("%d%d" ,&n,&m); int i,x,o=0 ; for (i=1 ; i<=3 *m+1 ; i++) scanf ("%d" ,&x),tuc[x]++; for (i=1 ; i<=n; i++) { tuc[i]++; if (check ()) o=1 ,printf ("%d " ,i); tuc[i]--; } if (!o) puts ("NO" ); return 0 ; }
T3 交作业(homework)
题意
一个人带着若干个物品奔跑,速度为每秒一个单位长度。有 n n n 个站点,第 i i i 个站点在位置 s i s_i s i 处,这个人要将 h i h_i h i 个物品放到此处,放下后这个人就不在带着这些物品奔跑了。
在时刻 t t t 把物品放到 i i i 站点处会增加 f i × t f_i\times t f i × t 的疲劳值,带着 k k k 个物品奔跑一个单位长度会增加 k k k 的疲劳值。
对于 20 % 20\% 2 0 % 的数据,n ≤ 20 n≤20 n ≤ 2 0 。
对于 70 % 70\% 7 0 % 的数据,n ≤ 100 n≤100 n ≤ 1 0 0 。
对于 100 % 100\% 1 0 0 % 的数据,n ≤ 1000 , ∣ s i ∣ ≤ 100 , 1 ≤ h i , f i ≤ 40 n\le 1000,|s_i|≤100,1≤h_i,f_i≤40 n ≤ 1 0 0 0 , ∣ s i ∣ ≤ 1 0 0 , 1 ≤ h i , f i ≤ 4 0 。
算法一
暴力深搜,每次枚举往左走或者往右走,时间复杂度为 O ( 2 n ) O(2^n) O ( 2 n ) ,空间复杂度为 O ( n ) O(n) O ( n ) ,期望得分 20 20 2 0 分。
算法二
首先肯定先以 s s s 为关键字排序。
很显然的一点,如果你经过一个站点却不放东西一定不是最优的。那么不论何时,已经处理好的站点的编号一定是一个连续的区间。
自然联想到区间 DP。设 d p i , j dp_{i,j} d p i , j 表示编号从 i i i 到 j j j 的站点都处理好时的最小疲惫值。但还有是在左边还是在右边的问题,于是再来一维: d p i , j , 0 / 1 dp_{i,j,0/1} d p i , j , 0 / 1 表示编号从 i i i 到 j j j 的老师都处理好且处在 i i i 或 j j j 时的最小疲惫值。
d p i , j , 1 / 0 dp_{i,j,1/0} d p i , j , 1 / 0 显然可以由 d p i + 1 , j , 1 / 0 dp_{i+1,j,1/0} d p i + 1 , j , 1 / 0 或 d p i , j − 1 , 1 / 0 dp_{i,j-1,1/0} d p i , j − 1 , 1 / 0 转移过来。 设 H i H_i H i 表示 h i h_i h i 的前缀和,F i F_i F i 表示 f i f_i f i 的前缀和。那么如果第 i i i 到 j j j 个站点已经处理完,此时带着 H n − H i − 1 + H j H_n-H_{i-1}+H_j H n − H i − 1 + H j 个物品,并且每秒疲劳值会增加 F n − F i − 1 + F j F_n-F_{i-1}+F_j F n − F i − 1 + F j 次。于是有转移方程:
f i , j , 0 = min { f i + 1 , j , 0 + ( s i + 1 − s i ) ( F n − F i + F j + H n − H i + H j ) , f i + 1 , j , 1 + ( s j − s i ) ( F n − F i + F j + H n − H i + H j ) } f_{i,j,0}=\min\{f_{i+1,j,0}+(s_{i+1}-s_i)(F_n-F_i+F_j+H_n-H_i+H_j),f_{i+1,j,1}+(s_j-s_i)(F_n-F_i+F_j+H_n-H_i+H_j)\}
f i , j , 0 = min { f i + 1 , j , 0 + ( s i + 1 − s i ) ( F n − F i + F j + H n − H i + H j ) , f i + 1 , j , 1 + ( s j − s i ) ( F n − F i + F j + H n − H i + H j ) }
剩下的同理,DP 的复杂度为 O ( n 2 ) O(n^2) O ( n 2 ) 。
我们枚举一下出发点,总时间复杂度 O ( n 3 ) O(n^3) O ( n 3 ) ,空间复杂度为 O ( n 2 ) O(n^2) O ( n 2 ) ,期望得分 70 70 7 0 分。
算法三
发现根本不需要枚举出发点,直接将 f i , i , 1 / 0 f_{i,i,1/0} f i , i , 1 / 0 全部设为 0 0 0 ,然后 DP 即可,时空复杂度均为 O ( n 2 ) O(n^2) O ( n 2 ) ,期望得分 100 100 1 0 0 分。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <stdio.h> #include <string.h> #include <algorithm> #define il inline #define int long long using namespace std;const int N=1005 ,I=0X3f3f3f3f ;int n,F[N],H[N],f[N][N][2 ];struct teacher {int s,h,f;}t[N];il bool cmp (teacher a,teacher b) {return a.s<b.s;}signed main () { freopen ("homework.in" ,"r" ,stdin),freopen ("homework.out" ,"w" ,stdout); scanf ("%lld" ,&n); int i,j,l; for (i=1 ; i<=n; i++) scanf ("%lld%lld%lld" ,&t[i].s,&t[i].h,&t[i].f); sort (t+1 ,t+n+1 ,cmp); for (i=1 ; i<=n; i++) F[i]=F[i-1 ]+t[i].f,H[i]=H[i-1 ]+t[i].h; memset (f,I,sizeof f); for (i=1 ; i<=n; i++) f[i][i][0 ]=f[i][i][1 ]=0 ; for (l=2 ; l<=n; l++) for (i=1 ; (j=i+l-1 )<=n; i++) f[i][j][0 ]=min (f[i+1 ][j][0 ]+(t[i+1 ].s-t[i].s)*(F[i]+F[n]-F[j]+H[i]+H[n]-H[j]),f[i+1 ][j][1 ]+(t[j].s-t[i].s)*(F[i]+F[n]-F[j]+H[i]+H[n]-H[j])), f[i][j][1 ]=min (f[i][j-1 ][1 ]+(t[j].s-t[j-1 ].s)*(F[i-1 ]+F[n]-F[j-1 ]+H[i-1 ]+H[n]-H[j-1 ]),f[i][j-1 ][0 ]+(t[j].s-t[i].s)*(F[i-1 ]+F[n]-F[j-1 ]+H[i-1 ]+H[n]-H[j-1 ])); printf ("%lld" ,min (f[1 ][n][0 ],f[1 ][n][1 ])); return 0 ; }
T4 数列的 F(seriesf)
改编自 2019 高中数学联赛二试第二题。
题意
有一个长度为 n n n 的整数数列 a i {a_i} a i ,且满足 1 = a 1 ≤ a 2 ≤ ⋯ ≤ a n − 1 ≤ a n = m 1=a_1≤a_2≤\cdots≤a_{n-1}≤a_n=m 1 = a 1 ≤ a 2 ≤ ⋯ ≤ a n − 1 ≤ a n = m 。
记 f = ( a 1 2 + a 2 2 + ⋯ + a n − 1 2 + a n 2 ) − ( a 1 a 3 + a 2 a 4 + ⋯ + a n − 2 a n ) f=(a_1^2+a_2^2+\cdots+a_{n-1}^2+a_n^2)-(a_1a_3+a_2a_4+\cdots+a_{n-2}a_n) f = ( a 1 2 + a 2 2 + ⋯ + a n − 1 2 + a n 2 ) − ( a 1 a 3 + a 2 a 4 + ⋯ + a n − 2 a n ) 。
求出 f f f 的最小值 f 0 f_0 f 0 ,并求出使 f = f 0 f=f_0 f = f 0 成立的 n n n 元组 ( a 1 , a 2 , … , a n − 1 , a n ) (a_1,a_2,\ldots,a_{n-1},a_n) ( a 1 , a 2 , … , a n − 1 , a n ) 的个数。
两个数都模 1000000007 1000000007 1 0 0 0 0 0 0 0 0 7 。
对于 50 % 50\% 5 0 % 的数据,m = 5 , 5 ≤ n ≤ 10 m=5,5≤n≤10 m = 5 , 5 ≤ n ≤ 1 0 。
对于 100 % 100\% 1 0 0 % 的数据,5 ≤ m ≤ n ≤ 100000 5≤m≤n≤100000 5 ≤ m ≤ n ≤ 1 0 0 0 0 0 且 m m m 为奇数。
算法一
直接暴力搜索每个位置填上什么数,时间复杂度为 O ( m n ) O(m^n) O ( m n ) ,空间复杂度为 O ( n ) O(n) O ( n ) ,期望得分 50 50 5 0 分。
算法二
以下是 恐怖的 数学推导。
由已知:
2 f = a 1 2 + a 2 2 + a n − 1 2 + a n 2 + ∑ i = 1 n − 2 ( a i + 2 − a i ) 2 2f=a_1^2+a_2^2+a_{n-1}^2+a_n^2+\sum\limits_{i=1}^{n-2}{(a_{i+2}-a_i)^2}
2 f = a 1 2 + a 2 2 + a n − 1 2 + a n 2 + i = 1 ∑ n − 2 ( a i + 2 − a i ) 2
因为 a i ( i = 1 , 2 , ⋯ , n ) a_i(i=1,2,\cdots,n) a i ( i = 1 , 2 , ⋯ , n ) 为整数且 1 = a 1 ≤ a 2 ≤ ⋯ ≤ a n − 1 ≤ a n = m 1=a_1\le a_2\le \cdots\le a_{n-1}\le a_n=m 1 = a 1 ≤ a 2 ≤ ⋯ ≤ a n − 1 ≤ a n = m ,
所以显然:
( a i + 2 − a i ) 2 ≥ a i + 2 − a i , a 1 2 ≥ a 1 , a 2 2 ≥ a 2 (a_{i+2}-a_i)^2\ge a_{i+2}-a_i,a_1^2\ge a_1,a_2^2\ge a_2
( a i + 2 − a i ) 2 ≥ a i + 2 − a i , a 1 2 ≥ a 1 , a 2 2 ≥ a 2
那么:
a 1 2 + a 2 2 + ∑ i = 1 n − 3 ( a i + 2 − a i ) 2 ≤ a 1 + a 2 + ∑ i = 1 n − 3 ( a i + 2 − a i ) = a n − 2 − a n − 1 a_1^2+a_2^2+\sum\limits_{i=1}^{n-3}{(a_{i+2}-a_i)^2}\le a_1+a_2+\sum\limits_{i=1}^{n-3}{(a_{i+2}-a_i)}=a_{n-2}-a_{n-1}
a 1 2 + a 2 2 + i = 1 ∑ n − 3 ( a i + 2 − a i ) 2 ≤ a 1 + a 2 + i = 1 ∑ n − 3 ( a i + 2 − a i ) = a n − 2 − a n − 1
再结合 a n − 2 ≤ a n − 1 ≤ a n = m a_{n-2}\le a_{n-1}\le a_n=m a n − 2 ≤ a n − 1 ≤ a n = m 便有:
2 f ≥ ( a n − a n − 2 ) 2 + a n − 1 2 + a n 2 + a n − 2 + a n − 1 ≥ ( m − a n − 2 ) 2 + a n − 2 2 + m 2 + 2 a n − 2 2f\ge (a_n-a_{n-2})^2+a_{n-1}^2+a_n^2+a_{n-2}+a_{n-1}\ge (m-a_{n-2})^2+a_{n-2}^2+m^2+2a_{n-2}
2 f ≥ ( a n − a n − 2 ) 2 + a n − 1 2 + a n 2 + a n − 2 + a n − 1 ≥ ( m − a n − 2 ) 2 + a n − 2 2 + m 2 + 2 a n − 2
f ≥ 1 2 ( m 2 − 2 m a n − 2 + a n − 2 2 + m 2 + 2 a n − 2 ) = a n − 2 2 − ( m − 1 ) a n − 2 + m 2 = ( a n − 2 − m − 1 2 ) 2 + 3 m 2 + 2 m − 1 4 f\ge \frac{1}{2}(m^2-2ma_{n-2}+a_{n-2}^2+m^2+2a_{n-2})=a_{n-2}^2-(m-1)a_{n-2}+m^2=(a_{n-2}-\frac{m-1}{2})^2+\frac{3m^2+2m-1}{4}
f ≥ 2 1 ( m 2 − 2 m a n − 2 + a n − 2 2 + m 2 + 2 a n − 2 ) = a n − 2 2 − ( m − 1 ) a n − 2 + m 2 = ( a n − 2 − 2 m − 1 ) 2 + 4 3 m 2 + 2 m − 1
又因为 m m m 为奇数,所以 m − 1 2 \frac{m-1}{2} 2 m − 1 与 3 m 2 + 2 m − 1 4 \frac{3m^2+2m-1}{4} 4 3 m 2 + 2 m − 1 均为整数。故当 a 1 = a 2 = 1 , a n − 1 = a n = m − 1 2 a_1=a_2=1,a_{n-1}=a_n=\frac{m-1}{2} a 1 = a 2 = 1 , a n − 1 = a n = 2 m − 1 且 a i + 2 − a i ∈ { 0 , 1 } ( i = 1 , 2 , ⋯ , n − 3 ) a_{i+2}-a_i\in \{0,1\}(i=1,2,\cdots,n-3) a i + 2 − a i ∈ { 0 , 1 } ( i = 1 , 2 , ⋯ , n − 3 ) 时,f f f 有最小值 f 0 = 3 m 2 + 2 m − 1 4 f_0=\frac{3m^2+2m-1}{4} f 0 = 4 3 m 2 + 2 m − 1 。
考虑组数,若要使等号成立,则要有 1 = a 1 ≤ a 2 ≤ ⋯ ≤ a n − 1 = m − 1 2 1=a_1\le a_2\le \cdots\le a_{n-1}=\frac{m-1}{2} 1 = a 1 ≤ a 2 ≤ ⋯ ≤ a n − 1 = 2 m − 1 ,并且对于每个 k ( 1 ≤ k ≤ m − 1 2 ) k(1\le k\le \frac{m-1}{2}) k ( 1 ≤ k ≤ 2 m − 1 ) ,a 1 , a 2 , ⋯ , a n − 1 a_1,a_2,\cdots,a_{n-1} a 1 , a 2 , ⋯ , a n − 1 中至少有两项等于 k k k ,易证这和上面的取等条件是等价的。
对于每个 k ( 1 ≤ k ≤ m − 1 2 ) k(1\le k\le \frac{m-1}{2}) k ( 1 ≤ k ≤ 2 m − 1 ) ,设 a 1 , a 2 , ⋯ , a n − 1 a_1,a_2,\cdots,a_{n-1} a 1 , a 2 , ⋯ , a n − 1 中等于 k k k 的项数为 1 + g k 1+g_k 1 + g k ,g k g_k g k 是正整数。
则有 ( 1 + g 1 ) + ( 1 + g 2 ) + ⋯ + ( 1 + g m − 1 2 ) = n − 1 (1+g_1)+(1+g_2)+\cdots+(1+g_{\frac{m-1}{2}})=n-1 ( 1 + g 1 ) + ( 1 + g 2 ) + ⋯ + ( 1 + g 2 m − 1 ) = n − 1 ,即 g 1 + g 2 + ⋯ + g m − 1 2 = 2 n − m − 3 2 g_1+g_2+\cdots+g_{\frac{m-1}{2}}=\frac{2n-m-3}{2} g 1 + g 2 + ⋯ + g 2 m − 1 = 2 2 n − m − 3 。
使等式成立的 m − 1 2 \frac{m-1}{2} 2 m − 1 元组 ( g 1 , g 2 , ⋯ , g m − 1 2 ) (g_1,g_2,\cdots,g_{\frac{m-1}{2}}) ( g 1 , g 2 , ⋯ , g 2 m − 1 ) 的个数为 ( m − 1 2 2 n − m − 3 2 ) \dbinom{\frac{m-1}{2}}{\frac{2n-m-3}{2}} ( 2 2 n − m − 3 2 m − 1 ) ,且每个 ( g 1 , g 2 , ⋯ , g m − 1 2 ) (g_1,g_2,\cdots,g_{\frac{m-1}{2}}) ( g 1 , g 2 , ⋯ , g 2 m − 1 ) 对应唯一的一个 ( a 1 , a 2 , ⋯ , a n ) (a_1,a_2,\cdots,a_n) ( a 1 , a 2 , ⋯ , a n ) ,所以组数是 ( m − 1 2 2 n − m − 3 2 ) \dbinom{\frac{m-1}{2}}{\frac{2n-m-3}{2}} ( 2 2 n − m − 3 2 m − 1 ) 。
然后我们就做完了这个大结论题 (逃) ,期望得分 100 100 1 0 0 分。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <stdio.h> #define il inline #define int long long #define N 100001 using namespace std;const int mod=1e9 +7 ; int n,m,fac[N],iac[N];il int ksm (int a,int b) { int res=1 ; for ( ; b; b>>=1 ,a=a*a%mod) if (b&1 ) res=res*a%mod; return res; } il int C (int x,int y) {return fac[x]*iac[y]%mod*iac[x-y]%mod;}signed main () { freopen ("seriesf.in" ,"r" ,stdin),freopen ("seriesf.out" ,"w" ,stdout); scanf ("%lld%lld" ,&n,&m); int i; for (i=fac[0 ]=1 ; i<N; i++) fac[i]=fac[i-1 ]*i%mod; for (i=n,iac[n]=ksm (fac[n],mod-2 ); i>=1 ; i--) iac[i-1 ]=iac[i]*i%mod; printf ("%lld\n%lld" ,(3ll *m*m+2ll *m-1ll )/4 %mod,C ((2 *n-m-3 )/2 ,(m-3 )/2 )); return 0 ; }