(HDU 4586)
思路:
很裸的一道概率题,容易得到公式ans=1/n*va[1]+1/n*va[2]+...+1/n*va[n]+m/n*ans,va[i]为对应位置得到的钱数,但是细节不得不注意!!第一次没看到无限多钱要输出inf,第二次没想到,即使n==m也不一定无限多钱,因为有可能每个面得到的钱数都是0.
#include#include int va[300];int main(){ int n,i,m,LL; while(scanf("%d",&n)!=EOF) { double ans=0; for(i=1;i<=n;i++){ scanf("%d",&va[i]); ans+=1.0*va[i]; } scanf("%d",&m); for(i=0;i
(HDU 4587)
思路:
图论渣渣...等学了图论再看..
(HDU 4588)
思路:
这题一直在想数位dp神马的,后来才发现其实是有规律的....1-n转化成2进制以后,每一位1出现都是循环的,所以可以直接求出1-n之间所有数转化成2进制后,每一位1的个数..然后就可以直接算进位的次数了.
#include#include long long sum[100];long long solve(int a,int b){ memset(sum,0,sizeof(sum)); long long cir=2; if(b>=0) { for(int i=1;i<=40;i++) { if(2*b (cir/2)) sum[i]+=temp-(cir/2); cir*=2; } } cir=2; if(a>=0) { for(int i=1;i<=40;i++) { if(2*a (cir/2)) sum[i]-=temp-(cir/2); cir*=2; } } long long ret=0; int pos=1; while(sum[pos]!=0) { ret+=sum[pos]/2; sum[pos+1]+=(sum[pos]/2); pos++; } return ret;}int main(){ int a,b; while(scanf("%d%d",&a,&b)!=EOF) { printf("%lld\n",solve(a,b+1)); } return 0;}
(HDU 4592)
思路:大家第一下一定都会想到枚举第一行的状态改变...目测这题卡的就是这种做法...TLE了好久,其实,不管哪种状态,最后都可以处理成,前n-1行全是0的状态,而第n行不确定,由于第n行的状态只有1<<n种,所以可以预处理出除了最后一行,其它行全是0时,哪种状态改变可以让第一行变成0,然后保存下来.以上预处理过后,求解每个棋盘的时候,第一行状态不变,从第二行开始向下先处理一遍,就变成了我们预处理过的状态,再用我们预处理出来的状态处理回去就可以全变成0了.当然,两次改变的位置是要异或一下的,因为按2下等于没按嘛.
#include#include #include #include using namespace std;#define INF 100000000int va[10],n,tem[10],NUM1[300],tem1[10],tem2[10];int MAP[10][300];vector road[10][300];int min(int x,int y){ return x >1)&0x55555555); n=(n&0x33333333)+((n>>2)&0x33333333); n=(n&0x0f0f0f0f)+((n>>4)&0x0f0f0f0f); n=(n&0x00ff00ff)+((n>>8)&0x00ff00ff); n=(n&0x0000ffff)+((n>>16)&0x0000ffff); return n;}void init(){ int i,j,k,r; for(i=0;i<=255;i++){ NUM1[i]=get1(i); } for(i=1;i<=8;i++) { int state=(1< >1); } for(j=0;j<=state;j++) { for(k=0;k<=state;k++) { memset(tem,0,sizeof(tem)); int pre=k; tem[1]=j^MAP[i][k]; for(r=2;r<=i;r++) { tem[r]^=pre; tem[r]^=MAP[i][tem[r-1]]; pre=tem[r-1]; } if(tem[i]==0) { road[i][j].push_back(k); } } } }}int make(int a[],int b[],int n,int sta)//初始状态,中间状态{ int r; memset(tem,0,sizeof(tem)); b[1]=sta; tem[1]=a[1]^MAP[n][sta]; for(r=2;r<=n;r++) { tem[r]=a[r]^b[r-1]; tem[r]^=MAP[n][tem[r-1]]; b[r]=tem[r-1]; } return tem[n];}int main(){ int T,i,j,ans; init(); scanf("%d",&T); while(T--) { scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&va[i]); memset(tem2,0,sizeof(tem2)); tem2[1]=make(va,tem1,n,0); ans=INF; for(i=0;i<(int)road[n][tem2[1]].size();i++) { make(tem2,va,n,road[n][tem2[1]][i]); int cnt=0; for(j=1;j<=n;j++) cnt+=NUM1[tem1[n-j+1]^va[j]]; ans=min(ans,cnt); } if(ans==INF) printf("-1\n"); else printf("%d\n",ans); } return 0;}
思路:
这个就略过了..
(HDU 4596)
思路:
看数据量一定是枚举任意2个虫洞有没有交集,对于2个虫洞,只要能找到x1*k1+a=x2*k2+b(k1,k2为任意整数)就说明有交集,对等式移项可得x1*k1-x2*k2=b-a,如果有整数解,那么(b-a)%gcd(x1,x2)应该等于0,否则无整数解,现在a的范围是[y1,z1],b的范围是[y2,z2],那么b-a的范围也可以确定下来,剩下的只要判断一下是否存在(b-a)%gcd(x1,x2)==0就行了,第一次写的时候没完全想清楚区间的转化,代码写的比较挫..
#include#include using namespace std;struct node{ int x,y,z;}va[1200];long long gcd(long long x,long long y){ while(x) { long long temp=x; x=y%x; y=temp; } return y;}int check(int i,int j){ if(va[i].x==va[j].x){ if(va[i].y