湘潭大学2017年下学期程序设计实践-模拟测试1 题解

XTU 1284 多项式

http://202.197.224.59/exam/index.php/problem/exam_read/id/1284/exam_id/227

思路:直接循环求解便可,注意长整型溢出的问题

(a+b)%m = a%m + b%m
可根据这个式子求解,另外注意多次方有可能溢出LL。

#include 
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<"\n";
    }
    return 0;
}

XTU 1285 探测器

http://202.197.224.59/exam/index.php/problem/exam_read/id/1285/exam_id/227

思路:只要从左到右依次遍历,遇到“0”就计数,并且把相邻的全都改成“1”,这样保证结果最优。

#include 
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;iif(s[i]=='0')
            {
                for(int j=max(0,i-2);j<=min(len-1,i+2);j++)
                {
                    s[j]='1';
                }
                ans++;
            }
        }
        cout<return 0;
}

XTU 1286 比赛

http://202.197.224.59/exam/index.php/problem/exam_read/id/1286/exam_id/227

思路:
我们要让冠军(假设为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 
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<return 0;
}

XTU 1287 银行

http://202.197.224.59/exam/index.php/problem/exam_read/id/1287/exam_id/227

思路:
一天一共24*60分钟,所以只需要遍历每一分钟发生了什么便可,这里需要熟练掌握优先队列的操作(主要是优先级的确定)

细节题,详见代码

#include 
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 pq;

    int qwq=1;
    int nows=0;

    for(int i=0;i<=3600;i++)//遍历每一分钟
    {
        while(p[qwq].s<=i && qwq//当此时此刻,顾客已经到达银行了,则加入队列,进行排队
            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;icout<" ";
        if(p[i].ok)
            cout<" Yes\n";
        else cout<" No\n";
    }

    return 0;
}

XTU 1288 Binary Search Tree

http://202.197.224.59/exam/index.php/problem/exam_read/id/1288/exam_id/227

思路:暴力建树然后暴力匹配,查看是否同构

主要考察BST应用能力。
不能动态指针建树,若不释放内存,会MLE;释放内存会TLE;
不能数组建树,n到达了100,所以最大树到达了2的100次方;
综上,用静态指针。

#include 
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<return 0;
}

XTU 1289 3的倍数

http://202.197.224.59/exam/index.php/problem/exam_read/id/1289/exam_id/227

暂时没做…好难啊

UPD:

XTU 1289 3的倍数

http://202.197.224.59/exam/index.php/problem/read/id/1289

思路:

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 
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'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;iif(s[i]=='0')
            {
                ans = ans-dp[i+1][0]-1;
                ans%=mod;
            }
        }
        cout<<(ans+mod)%mod<<"\n";
    }
    return 0;
}

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