XTU Monthly, April 2014(湘潭大学4月月赛)

比赛链接:

http://202.197.224.59/OnlineJudge2/index.php/Contest/problems/contest_id/31


^_^ 中文题目就不说题目意思啦。


Problem A  Number (XTU 1192)

题目链接:

http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1192

解题思路:

贪心。

如果n是偶数,直接除以2,如果是奇数,看+1还是-1所得数的2的因子个数多。3另外单独处理(是减一,不是加一)。

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

ll n;


int Ti(ll cur) //求出cur中因子2的个数
{
    int cnt=0;

    while(cur%2==0&&cur)
    {
        cnt++;
        cur/=2;
    }
    return cnt;

}
int main()
{
    while(~scanf("%I64d",&n))
    {
        int ans=0;

        while(n)
        {
            ans++;
            if(n%2==0) //是偶数直接除以2
            {
                n/=2;
                continue;
            }

            if(n==3||n==1)
            {
                n--;
                continue;
            }

            int a=Ti(n+1),b=Ti(n-1);

            if(a>b) //如果是+1 得到2的次数多
                n++;
            else  //如果次数相等或小于 选择小的
                n--;

        }
        printf("%d\n",ans);
    }

   return 0;
}

Problem B  Lukey Wheel (XTU 1193)

题目链接:

http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1193

解题思路:

概率dp.求期望+预处理。

至上限x=1000,y=1000. 从后往前考虑,dp[i][j]:表示已经获得i个一等奖,j个二等奖,到达获得1000个一等奖1000个二等奖还需转动次数的期望。

显然当i=1000时,dp[i][j]=1/8*(1+dp[i][j+1])+7/8*(1+dp[i][j])  也即:dp[i][j]=1/8*dp[i][j+1]+8 一等奖已经是上限了,再获得一等奖无贡献(即本身dp[i][j])。

同理当j=1000时,dp[i][j]=1/8*(1+dp[i+1][j])+7/8*(1+dp[i+1][j]) 也即:dp[i][j]=1/8*dp[i+1][j]+8 二等奖次数已达到上限,再获得二等奖无贡献(即本身dp[i][j])。

当i<1000&&j<1000时 dp[i][j]=1/8*(1+dp[i+1][j])+1/8*(1+dp[i][j+1]+6/8(1+dp[i][j]) 当前这次的转动要么是一等奖,要么是二等奖,要么都不是(即本身dp[i][j])。

输入一个x,y,直接输出dp[1000-x][1000-y]即可。

代码:

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 1100

double dp[Maxn][Maxn];

int main()
{
   int x,y;


   x=1000;
   y=1000;

      dp[x][y]=0;

      for(int j=y-1;j>=0;j--)
          dp[x][j]=8+dp[x][j+1];


      for(int j=x-1;j>=0;j--)
          dp[j][y]=8+dp[j+1][y];


       for(int i=x-1;i>=0;i--)
       {
           for(int j=y-1;j>=0;j--)
               dp[i][j]=1.0/2.0*(1+dp[i+1][j])+1.0/2.0*(1+dp[i][j+1])+3;
       }


   while(~scanf("%d%d",&x,&y))
       printf("%.6lf\n",dp[1000-x][1000-y]);

   return 0;
}


Problem C A+B (XTU 1194)

题目链接:

http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1194

解题思路:

裸的扩展欧几里得算法。

显然题目要求a*x+b*y=n,正整数<x,y>的对数。

分享一篇写的比较好的扩展欧基里德算法文章:http://chhaj5236.blog.163.com/blog/static/112881081200942542255916/

设k=gcd(a,b)

显然如果n不能被k整除,无解。方程可化简为a*x/(n/k)+b*y/(n/k)=gcd(a,b)=gcd(b,a%b)=b*x2+(a-a/b*b)*y2

x=n/k*x1 y=n/k*y1  x1=y2 y1=x2-a/b*y2

a,b,n同时除以gcd(a,b).

求出最小的正整数解x,a(x+p*b)+b*(y-p*a)=n. 只要满足a(x+p*b)<=n即可,也即p<=(n/a-x)/b 详细请见代码。

代码:

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

ll ex_gcd(ll a,ll b,ll &x,ll &y) //扩展欧几里德算法
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    ll g=ex_gcd(b,a%b,x,y);
    ll temp=x;

    x=y;
    y=temp-a/b*y;

    return g;
}

int main()
{
   ll a,b,n;

   while(~scanf("%I64d%I64d%I64d",&a,&b,&n))
   {
       if(a==b)
       {
           if(n%a==0)
               printf("1\n");
           else
               printf("0\n");
           continue;
       }

       ll x,y,bb;
       ll gg=ex_gcd(a,b,x,y);

       if(n%gg) //无解
       {
           printf("0\n");
           continue;
       }

       x=x*n/gg; //求出一个解
       y=y*n/gg;

       b=b/gg;
       a=a/gg;
       n/=gg;

       x=x%b;

       if(x<0)  //求出x的最小的正整数解
           x+=b;
       ll temp=(n-x*a)/b; //求出y

       //printf("::x:%I64d y:%I64d\n",x,temp);
       if(temp<0)  //此时y如果小于0的话,肯定不存在都是正整数的解
       {
           printf("0\n");
           continue;
       }

       printf("%d\n",(n/a-x)/b+1); //推出求个数的式子


   }
   return 0;
}



Problem D Hexa Kill

题目链接:

http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1195

解题思路:

拓扑排序+状压dp

先拓扑排序判断依赖关系是否有环。

dp[i]表示在走了状态为i的节点后,需要的最小的能量能量消化。预处理出每个节点的前驱(压缩成一个整数)。

dp[i|(1<<j)]=min(dp[i|(1<<j)],dp[i]+en[j][num[i]+1];

num[i]表示状态为i时,节点个数。

^-^-^  用二维矩阵保存就有问题,用vector就没问题,不知道什么原因,我怀疑这个oj的数据有问题。

代码:

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 21
int n,m;
int in[Maxn],dp[1<<Maxn],en[Maxn][Maxn];
int num[1<<Maxn];
int be[Maxn];
queue<int>myq;
vector<int>myv[Maxn];
//bool hav[Maxn][Maxn];

bool Tp() //拓扑排序判断是否有环
{
    while(!myq.empty())
        myq.pop();
    for(int i=1;i<=n;i++)
        if(!in[i])
            myq.push(i);
    int cnt=0;
    while(!myq.empty())
    {
        int temp=myq.front();
        myq.pop();
        cnt++;

       /* for(int i=1;i<=n;i++)
        {
            if(!in[i]||!hav[temp][i])
                continue;
            in[i]--;
            if(!in[i])
                myq.push(i);
        }*/
        for(int i=0;i<myv[temp].size();i++)
        {

            if(!(--in[myv[temp][i]]))
                myq.push(myv[temp][i]);
        }


    }
    if(cnt==n)
        return true;
    return false;

}

int main()
{
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);

   //printf("%d\n",(1<<18)*18);
   //system("pause");

   while(~scanf("%d%d",&n,&m))
   {
       memset(in,0,sizeof(in));
       memset(be,0,sizeof(be));
       memset(num,0,sizeof(num));
       //memset(hav,false,sizeof(hav));

       for(int i=1;i<=n;i++)
       {
           for(int j=1;j<=n;j++) //en[i][j]表示第i中材料第j步放需要的能量
           {
               scanf("%d",&en[i][j]);
               //hav[i][j]=false;
           }
           myv[i].clear();
       }

       for(int i=1;i<=m;i++)
       {
           int x,y;

           scanf("%d%d",&x,&y);
           in[x]++;
           be[x]|=(1<<(y-1)); //第x中材料的前驱材料状态
           //hav[y][x]=true;
           myv[y].push_back(x);
       }

       if(!Tp()) //有环
       {
           printf("Enemy Hexa Kill\n");
           continue;
       }
       memset(dp,INF,sizeof(dp));
       dp[0]=0;

       for(int i=0;i<(1<<n);i++) //
       {
           for(int j=1;j<=n;j++) //
           {
               if(dp[i]==INF) //当前状态不满足
                  continue;
               if((1<<(j-1))&i) //没有走到
                  continue;

               if((be[j]&i)==be[j]) //前驱状态满足
               {
                   if(dp[i]+en[j][num[i]+1]<dp[i|(1<<(j-1))])
                   {
                       dp[i|(1<<(j-1))]=dp[i]+en[j][num[i]+1];
                       num[i|(1<<(j-1))]=num[i]+1; //个数
                   }
               }
           }
       }

       printf("%d\n",dp[(1<<n)-1]);


   }
   return 0;
}
/*
5 5

2 3 2 1 1
1 2 1 3 3
2 1 3 3 3
1 2 1 2 1
1 1 2 1 1

2 3
2 4
5 4
1 2
1 5

*/





Problem E Tree

题目链接:

http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1196

解题思路: 

DFS+线段树(区间更新、单点查询)

对于节点u,增加d,它对子树节点v的影响是,(dep[v]-dep[u]+1)*d  化简得d*dep[v]+(1-dep[u])*d 显然对于每个点v,dep[v]是确定的,只用维护一个一次函数的两个系数即可。

每次更新时,只用更新子树节点区间的这个两个系数。

一遍DFS编号,确定每个节点所维护的区间范围,线段树更新。


=_=  =_= 不知道为什么用vector就RE,用邻接表就可以过,求大神指正。

代码:

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 110000

vector<int>myv[Maxn];
int to[Maxn],n,dep[Maxn],dd,q,from[Maxn];
ll ta,tb;
int cnt;

struct Node  //维护两个系数
{
    ll a,b;
}node[Maxn<<2];

struct Edge  //邻接表建树
{
    int v;
    struct Edge * next;
}edge[Maxn],*head[Maxn];

void add(int a,int b) //添加边
{
    ++cnt;
    edge[cnt].v=b;
    edge[cnt].next=head[a];
    head[a]=&edge[cnt];
}

void build(int l,int r,int rt)
{
    node[rt].a=node[rt].b=0;

    if(l==r)
        return ;

    int m=(l+r)>>1;

    build(lson);
    build(rson);
}
void pushdown(int rt)
{
    if(node[rt].a)
    {
        node[rt<<1].a+=node[rt].a;
        node[rt<<1|1].a+=node[rt].a;
        node[rt].a=0;
    }

    if(node[rt].b)
    {
        node[rt<<1].b+=node[rt].b;
        node[rt<<1|1].b+=node[rt].b;
        node[rt].b=0;
    }
}


int dfs(int cur,int hi) //返回子树的最大编号  ,求出每个节点维护的区间
{
    ++dd;
    from[cur]=to[cur]=dd; //编号
    dep[cur]=hi; //深度

    struct Edge * p=head[cur];
    //for(int i=0;i<myv[cur].size();i++)
    while(p)
    {
        int temp=dfs(p->v,hi+1);
        to[cur]=max(temp,to[cur]);
        p=p->next;
    }
    return to[cur];
}
void query(int x,int l,int r,int rt) //单点查询
{
    if(l==r)
    {
        ta=node[rt].a; //返回最终的两个系数
        tb=node[rt].b;
        return ;
    }
    pushdown(rt);
    int m=(l+r)>>1;

    if(x<=m)
        query(x,lson);
    else
        query(x,rson);

}
void update(int L,int R,ll va,ll vb,int l,int r,int rt) //更新区间的系数值
{
    if(L<=l&&R>=r)
    {
        node[rt].a+=va;
        node[rt].b+=vb;
        return ;
    }
    int m=(l+r)>>1;
    pushdown(rt);

    if(L<=m)
        update(L,R,va,vb,lson);
    if(R>m)
        update(L,R,va,vb,rson);
}

int main()
{
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);
   int t;

   scanf("%d",&t);
   while(t--)
   {
       scanf("%d",&n);

      /* for(int i=0;i<=n;i++)
            myv[i].clear();*/
       int tt;
       cnt=0;
       memset(head,NULL,sizeof(head));
       for(int i=1;i<=n;i++)
       {
           int temp;

           scanf("%d",&temp);
           //myv[temp].push_back(i);
           add(temp,i);

           if(temp==0)
             tt=i;
       }
       dd=0;
       dfs(tt,1);
       build(1,n,1);

       scanf("%d",&q);
       while(q--)
       {
           ll ord,x,d;

           scanf("%I64d",&ord);
           if(ord==2)
           {
               scanf("%I64d",&x);
               //x=from[x];
               //printf("x:%I64d %d\n",x,dep[x]);
               query(from[x],1,n,1); //单点查询
               printf("%I64d\n",ta*dep[x]+tb);
           }
           else
           {
               scanf("%I64d%I64d",&x,&d);
               //printf("x:%I64d %d\n",x,dep[x]);
               update(from[x],to[x],d,d*(1-dep[x]),1,n,1); //区间更新
           }

       }

   }
   return 0;
}






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值