湘潭大学2018年上学期程序设计实践模拟考试3 参考题解

这个博客不再更新,新博客地址请戳

体验1
军神太强啦,1小时屯6题,瞬间AK,接下来的90分钟一直在跟榜

体验2
A题原题,循环写得好就不麻烦,不然要写很多行,情况要想全并不难。
B题原题,有了上一场的提示之后,这题就不难了。
C题很简单(小声)。
D题卡掉了O(TNK*log(N))的方法,卡掉我5发logN ,不过还是可做。
E题水dp(组合数学)。
F题原题,记忆化搜索。

体验3
被DC两题卡到,认识到自己是个菜鸡选手。
D:
一开始写O(NN)的预处理 + map存答案
改成O(N
KlogN)的二分查找
再灵机一动想到了O(N
K)的做法
有惊无险
C:
一开始看成了卡特兰数,后来发现不对
没带笔纸,找学霸借了笔和纸后开始推公式
发现规律后一顿猛敲,然而蜜汁wa
结束后发现自己循环边界写错了
再也不贪图方便擅自改循环边界了

体验4
难度较上一场而言,难题偏简单,简单题偏难,很适合我这种菜鸡选手。

懒得说了,直接上题解吧。
由于172.22.112.249/exam进不去,看不到题面了


A
题意:给一个44的矩阵,外圈的格子可以旋转,每次转动1格,求最大22的小矩阵和。
思路:暴力。

#include 
using namespace std;

int main(){
    int t;cin>>t;
    int a[20];
    int b[]={6,7,10,11};
    int bg[]={1,2,3,4,8,12,16,15,14,13,9,5};
    while(t--){
        for(int i=1;i<=16;i++)cin>>a[i];
        int ans=a[6]+a[7]+a[10]+a[11];
        for(int i=0;i<4;i++){
            for(int j=0;j<12;j++){
                ans = max(ans , a[bg[(j)%12]]+a[bg[(j+1)%12]]+a[bg[(j+2)%12]]+a[b[i]]);
            }
        }
        for(int i=0;i<12;i++){
            ans = max(ans , a[bg[(i)%12]]+a[bg[(i+1)%12]] + a[6] + a[7]);
            ans = max(ans , a[bg[(i)%12]]+a[bg[(i+1)%12]] + a[11] + a[7]);
            ans = max(ans , a[bg[(i)%12]]+a[bg[(i+1)%12]] + a[10] + a[11]);
            ans = max(ans , a[bg[(i)%12]]+a[bg[(i+1)%12]] + a[6] + a[10]);
        }
        cout<

B
题意:找到最小的b,使得n在b进制下,数位上出现的每个数字的次数都相等。
思路:已知一定有解,不妨暴力枚举。

#include 
using namespace std;
typedef long long ll;
ll n;

bool check(ll a,ll b){
    int vis[65]={0};
    while(a){
        vis[a%b]++;
        a/=b;
    }
    int v=-1;
    for(int i=0;i<65;i++){
        if(v==-1){
            if(vis[i])v=vis[i];
        } else {
            if(vis[i] && vis[i]!=v)return 0;
        }
    }return 1;
}

int main(){
    int t;cin>>t;
    while(t--){
        cin>>n;
        for(int b=2;;b++){
            if(check(n,b)){
                cout<

C
题意:n个点的SB树有多少种(对1e9+7取模)?
思路:
首先我们枚举0到10的所有情况,发现:
n h[n]
0 1
1 1
2 2
3 1
4 4
5 4
6 4
7 1
8 8
9 16
10 32

做这种题,我喜欢先猜结论,再证明正确性。
画图的时候(这里没有图,要图自己画),我们发现这棵树最底层是可以活动的,
而所有非底层都要填满,所以对于2-1,4-1,8-1,这些值,答案一定为1。
那么我们就可以求出最底层有多少个可以活动的点。
因为要保持平衡,假设有rest个可以活动的点,那么我可以左边放rest/2个,剩余的放在右边。
这样我们发现,如果rest/2 != rest - rest/2的话,左右两棵树可以交换,所以结果还要*2。

那么可以在O(N)的复杂度下,算出前n项的结果。
其实可发现,rest/2对应的那棵树,跟前面算出来的树有着相同的分类方法。
自己画图体会吧

#include 
using namespace std;
typedef long long ll;
const ll mod  = 1e9+7;

int main(){
    ll h[1050];
    h[0]=1;
    for(int i=1;i<=1000;i++){
        int l=i/2,r=(i-1)/2;
        if(l==r)
            h[i]=h[l]*h[r]%mod;
        else h[i]=2*h[l]*h[r]%mod;
    }
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        cout<

D
题意:给一个序列a,给k次查询,每次给一个s,问有多少个区间[l,r],使得区间和等于s。
思路:
首先想到了O(N^2)求出所有的s,然后map记录下来,N=1e4 ,明显要超时。
然后想到对于k个查询,每次都遍历左边界,通过前缀和二分的方式找到右边界,
如果左边界到右边界这一段的和为s,答案+1,复杂度O(KNlogN)
还能把这个logN去除掉,用到的是类似于滑动窗户的方法。复杂度O(K*N)

#include 
using namespace std;

template
inline void read(T &ret){
    ret=0;
    char c=getchar();
    while(c>'9'||c<'0')c=getchar();
    ret = ret*10+c-48;
    while(c=getchar(),c>='0'&&c<='9'){
        ret=ret*10+c-48;
    }
}

int pre[10005];
int n,k,s,ans;
int a[10005];

int main(){
    int t;read(t);
    while(t--){
        read(n);read(k);
        pre[0]=0;
        for(int i=1;i<=n;i++){
            read(a[i]);
            pre[i]=pre[i-1]+a[i];
        }
        while(k--){
            read(s);
            ans=0;
            int l=1,r=1;
            while(l<=n&&r<=n){
                if(pre[r]-pre[l-1]==s){
                    ans++;
                    l++;r++;
                }
                else if(pre[r]-pre[l-1]>s){
                    l++;
                } else {
                    r++;
                }
            }
            cout<

E
题意:问有多少种到达(n,0)的波形。
思路:
很直观的dp,或者用组合数也能做,仁者见仁。
首先到达(0,0)的方法有1种。
到达(x,y)的方法有多少种呢,(x-1,y),(x-1,y-1),(x-1,y+1)都能到达(x,y)
种类数满足加法原理。

#include 
using namespace std;
typedef long long ll;

int main(){
    ll dp[110][110];
    int t;cin>>t;
    while(t--){
        memset(dp,0,sizeof dp);
        int n;cin>>n;
        dp[0][0+50]=1;
        for(int x=1;x<=n;x++){
            for(int y=2;y<=100;y++){
                dp[x][y]=max(dp[x][y],dp[x-1][y]+dp[x-1][y-1]+dp[x-1][y+1]);
            }
        }
        cout<

F:
原题,这篇博客里有。
https://blog.csdn.net/mmingfunnytree/article/details/78806763

写的不对的地方欢迎指正,转载请注明出处^ ^.

你可能感兴趣的:(XTU—程序设计实践网站)