男人八题系列
来源:互联网 发布:ipad版淘宝怎么开店 编辑:程序博客网 时间:2024/06/05 05:55
POJ 1742 Coins
这是一道多重背包的题目,题意大体是给你n中硬币,每种硬币分别有v[i]个。让你求出不超过m能组成的钱数种类。
一开始准备用多重背包写,发现写着写着就复杂了(背包不太会),O(n*m)的算法必然会超时,就想着用数组标记的方法去写了。1282MS,不算长也不算短,等以后更强再去优化吧。
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<string>#include<cmath>using namespace std;int dp[111111],w[111],v[111],map[111111];inline void RD(int &ret)//输入优化,后来发现对这题基本上没用{ char c; do { c=getchar(); } while(c<'0'||c>'9'); ret=c-'0'; while((c=getchar())>='0'&&c<='9') { ret=ret*10+(c-'0'); }}int main(){ int n,m,i,s,j; while(scanf("%d%d",&n,&m)) { s=0; if(n==0&&m==0) { break; } for(i=1; i<=n; ++i) { RD(w[i]); } for(i=1; i<=n; ++i) { RD(v[i]); } memset(map,0,sizeof(map));//数组标记 map[0]=1; for(i=1; i<=n; ++i) { memset(dp,0,sizeof(dp));//清空状态数组 for(j=w[i]; j<=m; ++j) { if(map[j]==0&&map[j-w[i]]==1&&dp[j-w[i]]<v[i])//状态转移 { map[j]=1; dp[j]=dp[j-w[i]]+1;//记录是否存在 s++;//记下次数 } } } printf("%d\n",s); } return 0;}
POJ1740 A New Stone Game
一道博弈题,题意就是可以选定多个石堆中的一堆,舍弃至少一个石子,然后可以把多个石子分配给其它石堆。然后谁拿走最后一堆获胜。
首先找必败态(1,1)为先手必败,然后往后推。对任意状态,把所有的堆从大到小排序,设为a[1],a[2],a[3]……,a[n]>0。
首先确定操作最大的一堆a[1]。把a[2]-a[3]个石子放到第3堆,a[4]-a[5]个石子放到第5堆,等等。
如果n是奇数,直接把剩下的石子扔掉。如果n是偶数,最后第一堆留an个石子,其余扔掉。
当n是奇数,扔掉的石子数为a[1]-(a[2]-a[3])-(a[4]-a[5])-……-(a[n-1]-a[n])=a[1]-a[2]+a[3]-a[4]+……+a[n-2]-a[n-1]+a[n]>=a[n]>0,操作必定成功。
当n是偶数,扔掉的石子数为a[1]-(a[2]-a[3])-(a[4]-a[5])-……-a[n]=a[1]-a[2]+a[3]-a[4]+……+a[n-1]-a[n]。操作不成功<=>扔掉的石子数为0<=>a[1]-a[2]=a[3]-a[4]=……=a[n-1]-a[n]=0,即当前已经为必败态。
所以综上所述:当石堆不成对时,先手必胜,成对时先手必败。。。
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<string>#include<cmath>using namespace std;int map[1001];int main(){ int n,x,f,i; while(scanf("%d",&n)) { if(n==0) { break; } memset(map,0,sizeof(map));//标记 while(n--) { scanf("%d",&x); map[x]++;//记录组数 } f=0; for(i=0;i<=100;++i) { if(map[i]%2==1)//判断是否成对 { f=1; break; } } if(f==1) { printf("1\n"); } else { printf("0\n"); } } return 0;}
POJ1737 Connected Graph
男人第三题,一道数论题,加上高精度,题意是给你n个点,让你求其中所有点连起来,没有交叉的所有情况数。由于有n个点,所以就是在n个点中取2个点就是所有的直线数,所有直线又有连和不连两种情况,所有总共有2^C(n,2)种情况。得到递推式f(n)=2^C(n,2)-(C(n,1)*f(1)+C(n,2)*f(2)+...+C(n,n-1)*f(n-1));
由于C++的高精度太神了,不太会,所以直接用JAVA飘过,不多说了,表示还可以打表,但是实在太辛苦就算了...
import java.io.*;import java.util.*;import java.math.*;import java.text.*;public class Main{ public static void main(String[] args) { Scanner cin=new Scanner(System.in); int n,i,j; BigInteger Cn[][]=new BigInteger[51][51]; BigInteger f[]=new BigInteger[51]; BigInteger t,tt; BigInteger a=new BigInteger("2"); for(i=0; i<=50; i++) { Cn[i][0]=Cn[i][i]=BigInteger.valueOf(1); } for(i=1; i<=50; i++) { for(j=1; j<i; j++) { Cn[i][j]=Cn[i-1][j-1].add(Cn[i-1][j]); } } f[1]=BigInteger.valueOf(1); f[2]=BigInteger.valueOf(1); for(i=3; i<=50; i++) { f[i]=BigInteger.valueOf(0); for(j=1; j<i; j++) { t=BigInteger.valueOf(0); t=f[j].multiply(f[i-j]).multiply(Cn[i-2][j-1]); tt=BigInteger.valueOf(1); t=t.multiply(a.pow(j).subtract(tt)); f[i]=f[i].add(t); } } while(cin.hasNext()) { n=cin.nextInt(); if(n==0) { break; } System.out.println(f[n]); } }}
POJ 1743 Musical Theme
求最大不重合子段。。过的人数在8题中算多,,但是由于一直不太懂后缀数组LCP,所以再看了罗穗骞大神的后缀数组后才勉强懂了一点,,sa数组和height数组我只是直接套的模板,最后需要二分求解。。。后缀数组反正还是不太懂(Orz罗大神),,,
1/2水男人。。。
#include<iostream>#include<cmath>#include<cstring>#include<string>#include<algorithm>#include<iomanip>#include<cstdio>using namespace std;int n;int a[20001],f[20001];int rank[20001],sa[20001],top[20001],tmp[20001],height[20001],wa[20001],wb[20001];int cmp(int *r,int a,int b,int l){ return r[a]==r[b]&&r[a+l]==r[b+l];}void makesa()//后缀数组模板{ int i,j,p=0,*t,*x=wa,*y=wb,m=200; for(i=0; i<m; i++) { top[i]=0; } for(i=0; i<n; i++) { top[x[i]=f[i]]++; } for(i=1; i<m; i++) { top[i]+=top[i-1]; } for(i=n-1; i>=0; i--) { sa[--top[x[i]]]=i; } for(j=1; p<n; j+=j,m=p) { for(p=0,i=n-j; i<n; i++) { y[p++]=i; } for(i=0; i<n; i++) { if(sa[i]>=j) { y[p++]=sa[i]-j; } } for(i=0; i<n; i++) { tmp[i]=x[y[i]]; } for(i=0; i<m; i++) { top[i]=0; } for(i=0; i<n; i++) { top[tmp[i]]++; } for(i=1; i<m; i++) { top[i]+=top[i-1]; } for(i=n-1; i>=0; i--) { sa[--top[tmp[i]]]=y[i]; } for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++) { x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } }}void makeheight(){ int j,i,k; for(i=1; i<=n; i++) { rank[sa[i]]=i; } for(i=0,k=0; i<n; height[rank[i++]]=k) { for(k?k--:0,j=sa[rank[i]-1]; f[i+k]==f[j+k]; k++); }}bool ok(int x){ int p,q,i; p=q=sa[1]; for(i=2; i<=n+1; ++i) { if(height[i]<x) { p=q=sa[i]; } else { p=min(p,sa[i]); q=max(q,sa[i]); if((q-p)>=x) { return true; } } } return false;}int main(){ int i,l,mid,h; while(scanf("%d",&n)) { if(n==0) { break; } for(i=0; i<n; ++i) { scanf("%d",&a[i]); } for(i=0; i<n-1; ++i) { f[i]=a[i+1]-a[i]+89; } a[n-1]=0; makesa(); n--; makeheight(); l=4; h=n/2+1; while(l<h) { mid=(l+h)/2; //cout<<mid<<endl; if(ok(mid)==true) { l=mid+1; } else { h=mid; } } if(l<5) { l=0; } printf("%d\n",l); } return 0;}
POJ 1738 An old Stone Game
GarsiaWachs算法,看了大牛的blog才知道原来还有这么神的算法,朴素地写得O(n*n)的复杂度。居然1A。。。
算法内容如下:设一个序列是A[0..n-1],每次寻找最小的一个满足A[k-1]<=A[k+1]的k,(方便起见设A[-1]和A[n]等于正无穷大)
那么我们就把A[k]与A[k-1]合并,之后找最大的一个满足A[j]>A[k]+A[k-1]的j,把合并后的值A[k]+A[k-1]插入A[j]的后面。
有定理保证,如此操作后问题的答案不会改变。
#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<cmath>using namespace std;int a[50001];int n,tmp,ans;void f(int tt)//直到找出全部{ int i,j,id=a[tt-1]+a[tt]; ans+=id; tmp--; for(i=tt;i<tmp;++i) { a[i]=a[i+1]; } for(i=tt-1;i>0&&a[i-1]<id;--i) { a[i]=a[i-1]; } a[i]=id; while(i>=2&&a[i]>=a[i-2]) { j=tmp-i; f(i-1); i=tmp-j; }}int main(){ int i; while(scanf("%d",&n)) { if(n==0) { break; } for(i=0;i<n;++i) { scanf("%d",&a[i]); } tmp=1; ans=0; for(i=1;i<n;++i) { a[tmp++]=a[i]; while(tmp>=3&&a[tmp-3]<=a[tmp-1])//找中间的小值 { f(tmp-2); } } while(tmp>1) { f(tmp-1); } printf("%d\n",ans); } return 0;}
POJ 1744 Elevator Stopping Plan
一道二分贪心题,需要比较选择不同楼层停下所花费的最短时间,设定每个楼层都停是最长的上限=14*(n-1)。
#include<iostream>#include<cmath>#include<cstring>#include<string>#include<algorithm>#include<iomanip>#include<cstdio>using namespace std;inline void RD(int &ret){ char c; do { c=getchar(); } while(c<'0'||c>'9'); ret=c-'0'; while((c=getchar())>='0'&&c<='9') { ret=ret*10+(c-'0'); }}inline void OT(int a){ if(a>=10) { OT(a/10); } putchar(a%10+'0');}int v[30001],mm;bool f(int x)//贪心比较{ int i=x/20+2,j,cnt=0; while(i<=mm) { while(i<=mm&&v[i]==0) { i++; } if(((i-1)*4+10*cnt)>x) { return false; } j=(x-10*cnt+20*i+4)/24; i=(x-10*cnt+16*j+4)/20+1; cnt++; } return true;}int main(){ int n,i,l,r,m,o,s; while(1) { RD(n); if(n==0) { break; } r=0; memset(v,0,sizeof(v)); for(i=0; i<n; ++i) { RD(o); r=max(r,o); v[o]=1; } l=0; mm=r; r=14*(r-1); while(l<=r)//二分 { m=(l+r)/2; if(f(m)==true) { s=m; r=m-1; } else { l=m+1; } } OT(s); printf("\n"); } return 0;}
POJ 1741 Tree
树的分治,数据结构的题一直不太会做,所以直到现在才A了这题,典型的树中点对统计,理解了好久才AC了。。。看了QZC大神的论文和PPT很有收获:传送门
最近一直在训练,所以代码变得喜欢用宏定义和输入优化这类的东西。。。
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<string>#include<cmath>#define mem(a,b) memset(a,b,sizeof(a))#define FOR(i,m,n) for(i=m;i<n;++i)using namespace std;inline void RD(int &ret){ char c; do { c=getchar(); } while(c<'0'||c>'9'); ret=c-'0'; while((c=getchar())>='0'&&c<='9') { ret=ret*10+(c-'0'); }}inline void OT(int a){ if(a>=10) { OT(a/10); } putchar(a%10+'0');}struct xl{ int x,y,z;}e[200001];int p,q,l,r,ans;int t[100001],d[100001],a[100001],b[100001];bool vis[100001];void dfs(int u,int de){ vis[u]=1; d[u]=de; int w=t[u],v; while(w!=-1) { v=e[w].x; if(!vis[v]) { dfs(v,de+1); } w=e[w].z; } if(d[u]>d[q]) { q=u; } if(d[u]==(d[q]+1)/2) { p=u; }}void dist(int u){ int i,j,w=t[u],s=l,t,v,sp,sq; vis[u]=1; a[l++]=0; t=l; while(w!=-1) { v=e[w].x; if(!vis[v]) { dist(v); FOR(i,t,l) { a[i]+=e[w].y; } j=l-1; FOR(i,s,t) { while(j>=t&&a[j]+a[i]>r) { j--; } ans+=j-t+1; } sp=s; sq=t; FOR(i,s,l) { if(sq==l||(sp<t&&a[sp]<a[sq])) { b[i]=a[sp++]; } else { b[i]=a[sq++]; } } for(i=s; i<l; i++) { a[i]=b[i]; } t=l; } w=e[w].z; } return ;}int main(){ int i,n,u,v,w; while(1) { RD(n); RD(r); if(n==0&&r==0) { break; } mem(t,-1); FOR(i,0,n-1) { RD(u); RD(v); RD(w); e[2*i].x=v; e[2*i].y=w; e[2*i].z=t[u]; t[u]=2*i; e[2*i+1].x=u; e[2*i+1].y=w; e[2*i+1].z=t[v]; t[v]=2*i+1; } mem(vis,0); q=1; dfs(1,0); mem(vis,0); dfs(q,0); mem(vis,0); ans=0; l=0; dist(p); OT(ans); printf("\n"); } return 0;}
- 男人八题系列
- ltc男人八题
- 男人八题
- 男人八题总结
- 男人八题coins
- POJ1741&&BZOJ1468 男人八题
- poj 楼天成的男人八题系列 A New Stone Game 博弈问题
- 楼教主男人八题之poj1743
- poj 1741 Tree 据说是男人八题
- POJ 1741(男人八题)
- POJ1742.Coins(背包DP && 男人八题)
- POJ 1741 Tree (男人八题
- POJ-1742-Coins-DP-男人八题
- POJ 1742(男人八题第一题)
- PKU1743 Musical Theme 楼教主男人八题之一
- poj 1739(男人八题之插头DP)
- poj1740(A New Stone Game+男人八题之一)
- poj1740-楼教主所谓的男人八题之一
- Adaboost+Haar分类器(二)
- 动态规划DP持续分析(update)
- hdu_1754 I Hate It
- uva146 ID Codes
- Google C++ Mocking Framework for Dummies 翻译
- 男人八题系列
- 监控 esxi 虚拟机
- java中操作数组的常用工具类
- 从头到尾彻底解析Hash表算法
- 《算法竞赛-训练指南》第一章-1.19_UVa 11549
- 一、我的emacs配置--适用c/c++和python开发(https://github.com/pein0119/emacs.d)
- HDU1847:Good Luck in CET-4 Everybody!
- 第一篇
- uva10098 Generating Fast, Sorted Permutation