四川第七届 E Rectangle

Rectangle

frog has a piece of paper divided into nn rows and mm columns. Today, she would like to draw a rectangle whose perimeter is not greater than kk.

There are 8 (out of 9) ways when n = m = 2, k = 6

There are 88 (out of 99) ways when n=m=2,k=6n=m=2,k=6

Find the number of ways of drawing.

Input

The input consists of multiple tests. For each test:

The first line contains 33 integer n,m,kn,m,k (1n,m5104,0k1091≤n,m≤5⋅104,0≤k≤109).

Output

For each test, write 11 integer which denotes the number of ways of drawing.

Sample Input

    2 2 6
    1 1 0
    50000 50000 1000000000

Sample Output

    8
    0
    1562562500625000000
解析:枚举矩形的长h,然后它在h的方向上就有n-h+1种放法,同时宽的最大值w即为k/2 - h,对于每个0~w的宽度wi,它在w方向上的放法有m-wi+1种,求和即为所求方案数

我推出了数学公式
n*m中a*b的种数:(n-a+1)*(m-b+1)+(m-a+1)*(n-b+1)
这样仍会超时:a不变,b变化,推出一个公式。
1^2+2^2+3^2+……+n^2=n*(n+1)*(2*t+1)/6;
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#define  ll long long
using namespace std;
int main()
{
    ll n,m,k;
    while(~scanf("%lld %lld %lld",&n,&m,&k))
    {
        ll s=0;
        ll temp;
        if(k<6&&k>=4) s=n*m;
        else if(k<4) s=0;
        else
        {
            if(n>m)
            {
                temp=n;
                n=m;
                m=temp;
            }
            for(ll a=1;a<=n;a++)
            {
                ll b=min(k/2-a,m);
                if(b>=a)
                {
                    s+=(n-a+1)*((m-a+1)+(m-b+1))*(b-a+1)/2;
                }
                b=min(k/2-a,n);
                if(b>=a)
                {
                    s+=(m-a+1)*((n-a+1)+(n-b+1))*(b-a+1)/2;
                }
            }
            ll t=min(k/4,n);
            t=min(t,m);
            ll ss=0;
            ss+=(t*(t+1)*(2*t+1))/6-(t+1)*t*(n+m+2)/2+(n*m+1+n+m)*t;//中间有重复的情况,a=b的算了两次
            s=s-ss;   
        }
        printf("%lld\n",s);
    }
    return 0;
}
也有更简单的思路:
#include <bits/stdc++.h>  
using namespace std;  
  
int main(){  
    #ifdef sxk  
        freopen("in.txt", "r", stdin);  
    #endif // sxk  
  
    long long n, m, k;  
    while(cin>>n>>m>>k){  
        k /= 2;  
        long long ans = 0;  
        for(int h=1; h<=n; h++){  
            int w = k - h;  
            if(w <= 0) break;  
            if(w > m) w = m;  
            ans += (n - h + 1) * (m + m-w+1)*w/2;    //对于每个h,在h方向上n-h+1种,在w方向上枚举wi求和为(m + m-w+1) * w / 2种  
        }  
        cout<<ans<<endl;  
    }  
    return 0;  
}  



猜你喜欢

转载自www.cnblogs.com/caiyishuai/p/8955121.html