ZOJ Monthly, August 2009 总结
容斥原理,刚开始一直苦于想不出后面 NBUN个数至少有一个不能整除怎么保证...后来还是ry提醒才想到,居然可以反过来想,假设这 NBUN个元素分别为a1,a2....a NBUN ,也就是只要不能整除Temp=lcm(a1,a2....a NBUN)就行了,然后对于剩下的NBLN个只要有一个可以整除就合法的元素直接容斥就可以了,在过程中要保证每次减掉能整除Temp的情况就编程裸容斥了,注意lcm可能爆long long,要特殊处理!!一直调到最后才AC,真心坑队友啊ToT..
ZOJ 3233
#include <iostream> #include <cstdio> #define INF 1000000000000000000LL using namespace std; int va[20],n;//n为不能整除的数 long long no,ans; long long gcd(long long x,long long y){ while(x){ long long temp=x; x=y%x; y=temp; } return y; } long long lcm(long long x,long long y){ return x/gcd(x,y)*y; } void dfs(int st,int cnt,long long now,long long x){ //下一个因子起始位置,当前因子数,当前和因子值,结尾数字 if(cnt>=1){ if(cnt&1){ long long dis; if(no>x) dis=0; else dis=x/lcm(now,no); long long temp=x/now-dis; ans+=temp; } else{ long long dis; if(no>x) dis=0; else dis=x/lcm(now,no); long long temp=x/now-dis; ans-=temp; } } for(int i=st;i<n;i++) dfs(i+1,cnt+1,va[i]/gcd(now,va[i])*now,x); } long long solve(long long x){ ans=0; dfs(0,0,1,x); return ans; } int main() { int m,i,j; long long st,end,a; while(scanf("%d%d%lld%lld",&n,&m,&st,&end)!=EOF){ if(n==0&&m==0&&st==0&&end==0) break; for(i=0;i<n;i++) scanf("%d",&va[i]); no=1; for(i=0;i<m;i++){ scanf("%lld",&a); no=lcm(a,no); if(no>INF){ //防溢出 for(j=i+1;j<m;j++) scanf("%lld",&a); no=end+1; break; } } printf("%lld\n",solve(end)-solve(st-1)); } return 0; }
简单推方程式,由题目给定的条件可以求出中间转折点的X坐标的方程,-(a+b)x02+2*b*d2*x0+h1=0,然后分别判定两个解是否满足题目的条件即可,注意,题目第一段有说到,在转折点不能往回跳!!这个地方被坑死了!
ZOJ 3235
#include<stdio.h> #include<math.h> double h1,h2,d1,d2,a,b; bool check(double x) { if(x<0||x>d2) return 0; if(x>d1){ if(h1-a*d1*d1>=h2) return 1; else return 0; } if(x<d1){ double y=-a*x*x+h1; double y2=-b*(d1-x)*(d1-x)+y; if(y2>=h2) return 1; else return 0; } } int main() { while(scanf("%lf%lf%lf%lf%lf%lf",&h1,&h2,&d1,&d2,&a,&b)!=EOF) { double A=-(a+b); double B=2*b*d2; double C=h1-b*d2*d2; double drt=B*B-4*A*C; if(drt<0){ printf("No\n"); continue; } drt=sqrt(drt); double x1=(-B-drt)/2/A,x2=(-B+drt)/2/A; if(check(x1)) printf("Yes\n"); else if(check(x2)) printf("Yes\n"); else printf("No\n"); } return 0; }
应该算是数论吧...真心弱爆了,每次赛后才会做又有什么用呢ToT,给出出现极值的n-1个坐标,也就是f(t)的导数f'(t)=0有n-1个解,我们可以表示成这样的形式:
f'(t)=(t-t1)*(t-t2)*...*(t-tn-1)
可以看出tn-1的系数一定是1,又因为f(t)里tn的系数是an,可以得到an*n=1,根据要求 an * n = 1,正好系数就是1/n
同样的,其它f(t)的项ti的系数也是f'(t)的ti-1项的系数除以i
还有一点就是系数可能爆longlong,这里直接对lcm(1,2,3,....32)取模即可
ZOJ 3237
#include<iostream> #include<cstdio> using namespace std; #define MOD 144403552893600LL long long va[40]; long long dp[36][36]; int get(long long x,long long div){ x=(x%MOD+MOD)%MOD; if(x%div==0) return 0; x=x%div; while(x<div) x*=10; return x/div; } int main() { int T,n,i,j; scanf("%d",&T); while(T--){ scanf("%d",&n); for(i=1;i<n;i++) scanf("%lld",&va[i]); dp[0][0]=1; for(i=1;i<n;i++){ dp[i][0]=(dp[i-1][0]*va[i])%MOD; for(j=1;j<=i;j++) dp[i][j]=(dp[i-1][j-1]+dp[i-1][j]*va[i])%MOD; } printf("0"); for(i=1;i<n;i++) printf(" %d",get(dp[n-1][i],i+1)); printf("\n"); } return 0; }