zoukankan      html  css  js  c++  java
  • 【2016常州一中夏令营Day3】

    小 W 摆石子
    【问题描述】
    小 W 得到了一堆石子,要放在 N 条水平线与 M 条竖直线构成的网格的交点上。因为小 M 最喜欢矩形了,小 W 希望知道用 K 个石子最多能找到多少四边平行于坐标轴的长方形,它的四个角上都恰好放着一枚石子。
    【输入格式】
    第一行三个整数 N,M,K。
    【输出格式】
    一个非负整数,即最多的满足条件的长方形数量。
    【输入输出样例】

    rectangle.in
    3 3 8
    rectangle.out
    5

    rectangle.in
    7 14 86
    rectangle.out
    1398

    【数据规模】
    对于 50%的数据:N<=30
    对于 100%的数据:N<=30000,保证任意两点不重合,K<=N*M

     

    题解

    暴力枚举即可

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    long long n,m,k,sum,ans;
    long long C(long long x){return x*(x-1)>>1;}
    long long maxx(long long a,long long b){return a>b?a:b;}
    long long work(long long x,long long y)
    {
        long long i,tans;
        tans=0;
        for(i=1;i<=y;i++)
            if(k/i+(bool)(k%i)<=x)
                tans=maxx(tans,C(k/i)*C(i)+C(k%i)*(k/i));    
            
        return tans;
    }
    
    int main()
    {
        int i,j;
        freopen("rectangle.in","r",stdin);
        freopen("rectangle.out","w",stdout);
        scanf("%d%d%d",&n,&m,&k);
        ans=maxx(work(n,m),work(m,n));
        printf("%lld",ans);
        return 0;
    }

    小 M 玩数列
    【问题描述】
    众所周知,小 M 的数学超级超级好,于是给小 W 出了一道题:
    给小 W 两个数 X,Y,其中 X ≤ Y≤ 2^31−1。
    小 W 任务就是求出 Fibonacci 数列第 X~Y 项的和除以 10000 的余数。
    然而小 W 是数学战五渣,于是只能把这个任务交给机智的你啦。
    【输入格式】
    第一行一个整数 T,表示数据组数。
    接下来 T 行,每行两个数 X,Y,意义如题所述。
    【输出格式】
    T 行,每行是一个询问的答案。
    【输入输出样例】

    fibonacci.in
    2
    1 5

    fibonacci.out
    127 255

    fibonacci.in
    1
    12

    fibonacci.out
    5976
    【数据规模】
    对于 80%的数据:T=1,Y<=10^6
    对于 100%的数据:T<=1000,Y<=2^31-1

     

    题解

    s[i]=s[i-1]+f[i]=s[i-1]+f[i-1]+f[i-2]

    矩乘优化即可

    $$
left[
egin{array}{c}
s[i]\
f[i]\
f[i-1]
end{array}

ight]
$$=
$$
left[
egin{array}{ccc}
1&1&1\
0&1&1\
0&1&0
end{array}

ight]^{i-2}
$$*
$$
left[
egin{array}{c}
s[2]\
f[2]\
f[1]
end{array}

ight]
$$

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define mod 10000
    using namespace std;
    struct hh
    {
        int a[5][5],n,m;
    };
    hh a,b,c;
    
    int t,l,r,suma,sumb,ans;
    int f[50005];
    
    hh mul(hh,hh);
    hh ff(hh,int);
    int main()
    {
        int i,j;
        freopen("fibonacci.in","r",stdin);
        freopen("fibonacci.out","w",stdout);
        scanf("%d",&t);
        a.m=a.n=b.n=3;
        b.m=1;
        for(j=1;j<=3;j++) a.a[1][j]=1;
        a.a[2][2]=a.a[2][3]=1;
        a.a[3][2]=1;
        b.a[1][1]=2;
        b.a[2][1]=b.a[3][1]=1;
        while(t--)
        {
            scanf("%d%d",&l,&r);
            if(l<=3) suma=l-1;
            else{c=mul(ff(a,l-3),b);suma=c.a[1][1];}
            if(r<=2) sumb=r;
            else{c=mul(ff(a,r-2),b);sumb=c.a[1][1];}
            ans=(sumb-suma+mod)%mod;
            printf("%d
    ",ans);
        }
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    
    hh mul(hh a,hh b)
    {
        int i,j,k;
        hh c;
        c.n=a.n;
        c.m=b.m;
        memset(c.a,0,sizeof(c.a));
        for(i=1;i<=c.n;i++)
          for(j=1;j<=c.m;j++)
            for(k=1;k<=c.n;k++)
             c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
        return c;
    }
    
    hh ff(hh a,int k)
    {
        int i,j;
        hh c;
        c.m=a.m;
        c.n=a.n;
        for(i=1;i<=min(c.n,c.m);i++) c.a[i][i]=1;
        for(i=1;i<=c.n;i++)
          for(j=1;j<=c.m;j++)
             if(i!=j) c.a[i][j]=0;
        while(k)
        {
            if(k&1) c=mul(a,c);
            a=mul(a,a);
            k>>=1;
        }
        return c;
    }

    小 W 计树
    【问题描述】
    小 W 千辛万苦做出了数列题,突然发现小 M 被困进了迷宫里。迷宫是一个有 N(2≤N≤1000)个顶点 M(N−1≤M≤N∗(N − 1)/2 ) 条边的无向连通图。设 dist1[i]表示在这个无向连通图中, 顶点 i 到顶点 1 的最短距离。为了解开迷宫,现在要求小 W 在这个图中删除 M − (N − 1)条边,使得这个迷宫变成一棵树。设 dist2[i]表示在这棵树中,顶点 i 到顶点 1 的距离。小 W 的任务是求出有多少种删除方案,使得对于任意的 i,满足 dist1[i]=dist2[i]。
    快点帮助小 W 救出小 M 吧!
    【输入格式】
    第一行,两个整数, N, M,表示有 N 个顶点和 M 条边。
    接下来有 M 行,每行有 3 个整数 x, y, len(1 ≤ x, y ≤ n, 1 ≤ len ≤ 100),表示顶点 x 和顶点 y 有一条长度为 len 的边。
    数据保证不出现自环、重边。
    【输出格式】
    一行两个整数,表示满足条件的方案数 mod 2147483647 的答案。
    【输入输出样例】
    treecount.in
    3 3
    1 2 2
    1 3 1
    2 3 1

    treecount.in
    2
    【样例解释】
    删除第一条边或第三条边都能满足条件,所以方案数是 2。

    【数据规模】
    对于 30%的数据:2≤N≤5,M≤10
    对于 50%的数据:满足条件的方案数不超过 10000
    对于 100%的数据:2≤N≤1000

     

    题解

    首先考虑离 1 点最近的那个点,一定和 1 点只连着一条边,则这条边是必选的;然后考察第二近的点,一种可能是和 1 点直接连的边比较近,一种可能是经过刚才最近的那个点再到 1 点的路比较近,不管是哪一种,选择都是唯一的,而剩下第三种可能是两者距离相同,这样的话两者选且只能选一个。以此类推,假设现在已经构造好了前 k 个点的一棵子树,看剩余点中到 1 点最近的点,这个点到 1 点有 k 种方法(分别是和那 k 个点连边), 其中有 m 个是可以保持最短距离的,则这一步可选的边数就是 m。一直构造,把方法数累乘,就能得到最后的结果。整个过程可以很好的符合 dijkstra 的过程,而生成树的步骤和 prim 如出一辙。

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define mod 2147483647
    using namespace std;
     
    int n,m;
    bool v[1005];
    int we[1010][1010], dis[1010];
    int last[1010];
    int tot=0;
    struct hh
    {
        int next,to,w;
    }e[2000005];
    
    long long ans=1;
    struct node 
    {
        int id,d;
    };
    node a[1005];
    queue<int> q;
     
    bool cmp(node a, node b) 
    {
        return a.d < b.d;
    }
     
    void add(int a,int b,int c) 
    {
        tot++;
        e[tot].to=b;
        e[tot].w=c;
        we[a][b]=c;
        e[tot].next=last[a];
        last[a]=tot;
    }
    
    void spfa()
    {
        int i,now;
        for(i=2;i<=n;i++) dis[i]=9999999;
        q.push(1); 
        dis[1]=0;
        while(!q.empty()) 
        {
            now=q.front(); 
            q.pop(); 
            v[now]=false;
            for(i=last[now];i;i=e[i].next) 
                if(dis[e[i].to]>dis[now]+e[i].w) 
                {
                    dis[e[i].to]=dis[now]+e[i].w;
                    if(!v[e[i].to]) 
                    {
                        v[e[i].to]=true;
                        q.push(e[i].to);
                    }
                }
        }
    }
    
    int main() 
    {
        int i,j,x,y,z,now;
        freopen("treecount.in","r",stdin);
        freopen("treecount.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++) 
         for(j=1;j<=n;j++) 
          we[i][j]=9999999;
        for(i=1;i<=m;i++) 
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        spfa();
        for (i=1;i<=n;i++)
        {
            a[i].id=i;
            a[i].d=dis[i];
         } 
        sort(a+1,a+n+1,cmp);
        for(i=2;i<=n;i++) 
        {
            now=0;
            for(j=1;j<=i-1;j++) 
                if(a[i].d==a[j].d+we[a[i].id][a[j].id]) now++;
            ans=ans*(long long)now%mod;
        }
        printf("%lld",ans);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    Java 给Word指定字符串添加批注
    Java 打印Word文档
    Java 在PDF中添加页面跳转按钮
    C# 添加、修改、删除Excel图表数据标签
    C# 添加、读取、删除Excel文档属性
    Java 操作Word表格——创建嵌套表格、添加/复制表格行或列、设置表格是否禁止跨页断行
    【Luogu5348】密码解锁(莫比乌斯反演,数论)
    AtCoder Grand Contest 015
    AtCoder Grand Contest 014
    Codeforces Round #556 (Div. 1)
  • 原文地址:https://www.cnblogs.com/yljiang/p/5796904.html
Copyright © 2011-2022 走看看