zoukankan      html  css  js  c++  java
  • bzoj3505 [Cqoi2014]数三角形——组合数+容斥

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3505

    好题啊好题...好像还曾经出现在什么智力测试卷中来着...当时不会现在还是无法自己推出来...

    自己初步的想法是分类成有两点在一条横线上的和三点在不同横线上的;

    第一类就是枚举两条横线,枚举有两点的横线上的两个位置,枚举另一点在横线上的位置,再交换两条横线;

    也就是 C(n,2) * C(m,2) * m * 2;

    第二类就枚举三条横线,再枚举三个位置;

    也就是 C(n,3) * m * m * (m-1);

    然后发现不一定 m-1,万一前两个点确定的横线在第三条横线上没有整点呢!

    枚举? gcd?好像都不行...于是就萎了...

    题解是随便选情况减去一条线情况,一条线分横线竖线和斜线;

    对于斜线,确定一个点 (0,0),枚举一个(左下角)点 (i,j),计算一个(对角线)点 gcd(i,j)-1;

    再把这个矩形平移,也就是 * (n-i) * (m-j);

    再分斜线的方向,也就是 * 2;

    所以枚举 i , j ,ans -= 2 * (gcd(i,j)-1) * (n-i)  *(m-j);

    看博客:https://www.cnblogs.com/Var123/p/5377616.html

    还有:https://blog.csdn.net/u012288458/article/details/48624859

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    int const maxn=1e6+5;
    ll n,m;
    ll ans;
    ll c(ll x)
    {
    ////    c[1][1]=1;
    //    for(ll i=0;i<=n;i++)c[i][0]=1;
    //    for(ll i=2;i<=maxn;i++)
    //        for(int j=1;j<=3&&i>=j;j++)
    //            c[i][j]=c[i-1][j]+c[i-1][j-1];
        return x*(x-1)*(x-2)/6;//C(x,3)
    }
    ll gcd(ll a,ll b){return a%b?gcd(b,a%b):b;}
    int main()
    {
        scanf("%lld%lld",&n,&m); n++; m++;
        ans=c(n*m)-c(n)*m-c(m)*n;
        for(ll i=1;i<n;i++)//从0开始算点 
            for(ll j=1;j<m;j++)
                ans-=2*(gcd(i,j)-1)*(n-i)*(m-j);
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    第十四周学习进度
    第十三周学习进度
    第十二周学习进度条
    从用户体验角度评价所使用的输入法。
    个人博客十
    数组测试 --Junit
    看了build to win之后的感想
    思考题
    数组中最大子数组之和
    使用Espresso进行UI测试
  • 原文地址:https://www.cnblogs.com/Zinn/p/9260597.html
Copyright © 2011-2022 走看看