ZOJ Monthly, August 2009 总结

C.Lucky Number

  容斥原理,刚开始一直苦于想不出后面 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;
}

 

 E.Prototype

  简单推方程式,由题目给定的条件可以求出中间转折点的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;
}

 

G.Signals and Systems

  应该算是数论吧...真心弱爆了,每次赛后才会做又有什么用呢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;
}

 

posted @ 2013-04-30 20:12  破晓べ  阅读(320)  评论(0编辑  收藏  举报