1. 程式人生 > >湘潭大學2017年下學期程式設計實踐-模擬測試1 題解

湘潭大學2017年下學期程式設計實踐-模擬測試1 題解

XTU 1284 多項式

思路:直接迴圈求解便可,注意長整型溢位的問題

(a+b)%m = a%m + b%m
可根據這個式子求解,另外注意多次方有可能溢位LL。

#include <bits/stdc++.h>
using namespace std;

#define  ll __int64

int n,m,x;
int a[100];

ll qpow(ll a,ll n)//記得每次要對值取模
{
    ll ret=1;
    while(n)
    {
        if(n&1)
            ret=ret*a%m;
        a=a*a
%m; n>>=1; } return ret; } int main() { int t; cin>>t; while(t--) { scanf("%d%d%d",&n,&m,&x); ll ans = 0; for(int i=n;i>=0;i--) { scanf("%d",a+i); ans = (ans + (ll)a[i]*(ll)qpow(x,i))%m
; } cout<<ans<<"\n"; } return 0; }

XTU 1285 探測器

思路:只要從左到右依次遍歷,遇到“0”就計數,並且把相鄰的全都改成“1”,這樣保證結果最優。

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int t;
    cin>>t;

    while(t--)
    {
        int n;
        scanf("%d",&n);
        char
s[100]; scanf("%s",s); int len=strlen(s); int ans=0; for(int i=0;i<len;i++) { if(s[i]=='0') { for(int j=max(0,i-2);j<=min(len-1,i+2);j++) { s[j]='1'; } ans++; } } cout<<ans<<endl; } return 0; }

XTU 1286 比賽

思路:
我們要讓冠軍(假設為1號)打儘量多的比賽,那麼就要儘量多的給1號創造對手,根據題意可知:

要創造一個0級的對手不需要額外消耗
創造一個1級對手需要額外消耗1個0級的對手
而冠軍(1號)想要升到2級,只需要搞定2個0級的對手:0 vs 0 和 1 vs 0

根據前面的推斷可知,打的對手等級越低,消耗的對手人數越少,從而能讓1號打儘可能多的比賽。

因此

1號的等級 對手的等級
0 0
1 0
2 1
3 2

而我們可知:
對手要上1級,需要2個0級的對打
對手要上2級,需要1個1級打敗1個0級
對手要上3級,需要1個2級打敗一個1級
……

於是見程式碼:

#include <bits/stdc++.h>
using namespace std;
#define ll __int64
ll csa[1000];
void init()
{
//csa[i]表示產生一個等級i的對手需要消耗多少對手。
    csa[0]=1;
    csa[1]=2;
    for(int i=2;i<1000;i++)
    {
        csa[i] = csa[i-1]+csa[i-2];
    }
}

int main()
{
    init();
    ll n;
    while(cin>>n)
    {
        n--;
        int ans=0;
        if(n==0)
        {
            ;
        }
        else if(n==1)
        {
            ans++;
        }
        else if(n==2)
        {
            ans+=2;
        }
        else
        {
            n-=2;
            ans+=2;
            for(int i=2;n>=0;i++)
            {
                if(csa[i-1]<=n)
                    ans++;
                n-=csa[i-1];
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

XTU 1287 銀行

思路:
一天一共24*60分鐘,所以只需要遍歷每一分鐘發生了什麼便可,這裡需要熟練掌握優先佇列的操作(主要是優先順序的確定)

細節題,詳見程式碼

#include <bits/stdc++.h>
using namespace std;

struct node
{
    string id;//編號
    int i;//是當天第一個到銀行的
    int s;//什麼時候到達銀行的
    int t;//辦理時長
    int d;//最長等待時長
    int wt;//等了多久
    bool ok;//等到沒有
    node(){}
    node(string id,int i,int s,int t,int d):id(id),i(i),s(s),t(t),d(d),ok(0){}
    friend bool operator < (node a,node b)
    {
        if(a.id[0]!=b.id[0])
        {
            return a.id[0]!='V';
        }
        return a.s>b.s;
    }
}p[300];

int main()
{
    int cnt=1;
    string id;
    int h,m;
    int t;
    int d;
    char c;

    while(cin>>id>>h>>c>>m>>t>>d)
    //讀入資料,把時間處理成h*60+m的形式
        p[cnt++]=node(id,cnt,h*60+m,t,d);

    priority_queue<node> pq;

    int qwq=1;
    int nows=0;

    for(int i=0;i<=3600;i++)//遍歷每一分鐘
    {
        while(p[qwq].s<=i && qwq<cnt)
        //當此時此刻,顧客已經到達銀行了,則加入佇列,進行排隊
            pq.push(p[qwq++]);

        if(nows<=i)
        {
            while(!pq.empty() && pq.top().s + pq.top().d < nows )
                pq.pop();//當等了d分鐘還沒有排到,離開佇列
            if(pq.empty())continue;

            node tmp = pq.top();//隊首的顧客排到了
            pq.pop();

            p[tmp.i].ok=1;
            p[tmp.i].wt=i - tmp.s;

            nows = i + tmp.t;
        }
    }
    for(int i=1;i<cnt;i++)
    {
        cout<<p[i].id<<" ";
        if(p[i].ok)
            cout<<p[i].wt<<" Yes\n";
        else cout<<p[i].d<<" No\n";
    }

    return 0;
}

XTU 1288 Binary Search Tree

思路:暴力建樹然後暴力匹配,檢視是否同構

主要考察BST應用能力。
不能動態指標建樹,若不釋放記憶體,會MLE;釋放記憶體會TLE;
不能陣列建樹,n到達了100,所以最大樹到達了2的100次方;
綜上,用靜態指標。

#include <bits/stdc++.h>
using namespace std;

struct node
{
    int v;
    node *l,*r;
    void init()
    {
        l=r=0;
    }
}tree1[10005],tree2[10005];
int cnt,cnt2;

inline node* newnode1(int val)
{
    tree1[cnt].init();
    tree1[cnt].v=val;
    return &tree1[cnt++];
}

inline node* newnode2(int val)
{
    tree2[cnt2].init();
    tree2[cnt2].v=val;
    return &tree2[cnt2++];
}



void build(node* u,int val)
{
    if(val < u->v)
    {
        if(u->l!=NULL)
            build(u->l,val);
        else
            u->l = newnode1(val);
    }
    else
    {
        if(u->r!=NULL)
            build(u->r,val);
        else
            u->r = newnode1(val);
    }
}

void build2(node* u,int val)
{
    if(val < u->v)
    {
        if(u->l!=NULL)
            build2(u->l,val);
        else
            u->l = newnode2(val);
    }
    else
    {
        if(u->r!=NULL)
            build2(u->r,val);
        else
            u->r = newnode2(val);
    }
}

bool _istongG(node* t1,node* t2)
{
    if(t1==NULL || t2==NULL)
        return t1==NULL && t2==NULL;
    return _istongG(t1->l, t2->l) && _istongG(t1->r, t2->r);
}

int main()
{
    int t;
    int n,m;
    cin>>t;
    int a[1001];
    while(t--)
    {
        cnt=1;
        scanf("%d%d",&n,&m);
        scanf("%d",&a[1]);
        node *root = newnode1(a[1]);
        for(int i=2;i<=n;i++)
        {
            scanf("%d",a+i);
            build(root,a[i]);
        }

        for(int i=1;i<=m;i++)
        {
            cnt2=1;
            scanf("%d",&a[1]);
            node *root2 = newnode2(a[1]);
            for(int j=2;j<=n;j++)
            {
                scanf("%d",a+j);
                build2(root2,a[j]);
            }
            printf("%d: %s",i,((_istongG(root,root2))?"Yes\n":"No\n"));
        }
        cout<<endl;
    }
    return 0;
}

XTU 1289 3的倍數

暫時沒做…好難啊

UPD:

XTU 1289 3的倍數

思路:

1.我們知道,一個數字是3的倍數,當且僅當這個數字的數位和能整除3,那麼我們只需要找出那些使得數位和能整除3的種類。

2.
dp[i][j]表示以第i個數字為數字的開頭,能構成多少種符合條件的數字(此時不考慮前導0)
那麼有遞推式:
①:當前位模3餘0:
dp[i][0]=dp[i+1][0]<<1|1;
dp[i][1]=dp[i+1][1]<<1;
dp[i][2]=dp[i+1][2]<<1;

②:當前位模3餘1:
dp[i][0]=dp[i+1][0]+dp[i+1][2];
dp[i][1]=dp[i+1][1]+dp[i+1][0]+1;
dp[i][2]=dp[i+1][2]+dp[i+1][1];

③:
dp[i][0]=dp[i+1][0]+dp[i+1][1];
dp[i][1]=dp[i+1][1]+dp[i+1][2];
dp[i][2]=dp[i+1][2]+dp[i+1][0]+1;

此時,對於這個數字,dp[0][0]就是要求的答案。

3.問題在於如何去除含有前導0的種類數:
對於s[i]==0:
它的種類數應該是dp[i+1][0]+1;
(當前位是0,後面要湊成3的倍數,共有dp[i+1][0]種,然後後面全部不選,只選第i也滿足,故種類數是dp[i+1][0]+1)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9+7;
int main()
{
    char s[10000];
    int v[10000];
    ll dp[10000][3];
    while(scanf("%s",s)!=EOF)
    {
        int len=strlen(s);
        for(int i=0;i<len;i++)
            v[i] = (s[i]-'0')%3;
        dp[len][0]=dp[len][1]=dp[len][2]=0;
        for(int i=len-1;i>=0;i--)
        {
            if(v[i]==0)
            {
                dp[i][0]=dp[i+1][0]<<1|1;
                dp[i][1]=dp[i+1][1]<<1;
                dp[i][2]=dp[i+1][2]<<1;
            }
            else if(v[i]==1)
            {
                dp[i][0]=dp[i+1][0]+dp[i+1][2];
                dp[i][1]=dp[i+1][1]+dp[i+1][0]+1;
                dp[i][2]=dp[i+1][2]+dp[i+1][1];
            }
            else
            {
                dp[i][0]=dp[i+1][0]+dp[i+1][1];
                dp[i][1]=dp[i+1][1]+dp[i+1][2];
                dp[i][2]=dp[i+1][2]+dp[i+1][0]+1;
            }
            dp[i][0]%=mod;dp[i][1]%=mod;dp[i][2]%=mod;
        }
        ll ans=dp[0][0];
        for(int i=1;i<len;i++)
        {
            if(s[i]=='0')
            {
                ans = ans-dp[i+1][0]-1;
                ans%=mod;
            }
        }
        cout<<(ans+mod)%mod<<"\n";
    }
    return 0;
}