XTU Monthly, April 2014(湘潭大学4月月赛)
来源:互联网 发布:docker nginx 镜像 编辑:程序博客网 时间:2024/05/21 06:57
比赛链接:
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 1100double 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;}
题目链接:
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 21int 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 52 3 2 1 11 2 1 3 32 1 3 3 31 2 1 2 11 1 2 1 12 32 45 41 21 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 110000vector<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;}
- XTU Monthly, April 2014(湘潭大学4月月赛)
- XTU Monthly, April 2014
- XTU (湘潭大学) 2011 新生练习赛(第一场)/ 解题报告 4.4
- XTU (湘潭大学) 2011 新生练习赛(第一场)/ Problem A连续自然数和
- XTU (湘潭大学) 2011 新生练习赛(第一场)/ Problem CSBB的烦恼
- XTU (湘潭大学) 2011 新生练习赛(第一场)/ Problem H子段和计数
- XTU (湘潭大学) 2011 新生练习赛(第一场)/ Problem B N! Last non zero
- XTU 1203 A simple problem (2014 湖南湘潭邀请赛 A题)(数学)
- 湘潭大学新生赛总结
- Echo (湘潭大学OJ)
- Digit(湘潭大学比赛)
- XTU 1235 CQRXLB 2015嘉杰信息杯 湘潭赛
- Encode String&&湘潭大学月赛
- 20161217湘潭大学新生赛B题
- Collatz Conjecture(湘潭大学OJ)
- 湘潭大学OJ1200ProblemCRC(摸拟,坑题)
- 2015 湘潭大学程序设计比赛(Internet)
- 湘潭大学oj 1195
- 产生随机组丢到txt中
- 阅读《游戏引擎架构》一书--20140414
- start_jQuery{try}
- c3p0数据源的使用初步及Mysql8小时问题解决
- 第一周 Test Hello
- XTU Monthly, April 2014(湘潭大学4月月赛)
- 2013腾讯编程马拉松初赛第〇场(HDU 4504)威威猫系列故事——篮球梦
- Java类体中的this和super的用法
- 黑马程序员—Java IO流(File对象)
- tomcat中配置使用c3p0
- Problem A. Magic Trick解答
- Linux常用命令大全
- HDU 3397 Sequence operation(线段树)
- (6)顺序队列(Java)