BC-40 HDU5225 HDU 5226 【水】

第一题,给你一个矩形的面积,求矩形的最小周长。

可知,当两边长最接近的时候,周长最小。所以可以从sqrt(s)开始枚举,如果能够整除,就输出计算的周长

#include <stdio.h>
#include <math.h>
#define ll __int64
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ll n;
        scanf("%I64d",&n);
        ll tmp=sqrt(n),i;
        for(i=tmp;i<=n;i++)
            if(n%i==0) break;
        printf("%I64d\n",(i+n/i)*2);
    }
    return 0;
}

第二题,给你一串n长的序列。序列中数字是1-n。求所有字典序比给定序列小的序列的逆序数之和。

字典序大小定义:比较第一个不相同的数字,数字小的字典序小。如果序列比完了,那么长度小的字典序小。

这道题。。想了半个小时。。的样子?啊!我知道怎么做了!然后各种debug各种WA。。。。到了第二天。。。。终于。。。我在想我的心思为什么如此不缜密。。。

这样的,对于一串序列,例:

10

5 3 6 7 2 9 8 1 4 10


额,在举例之前要说,对于n个数的全排列的逆序数之和显然是固定的,这里可以推出公式来,设cal[i]为i个数的全排列的逆序数的和。

在枚举的时候可以把序列分成三部分。
通过统计可以得到比对到第i个数的时候,(i,n]中比a[i]小的个数(j),那么就有j*A[n-i]中排列使得字典序比原序列小。
对于每一个比a[i]小的数的序列中,我们已经知道在A[n-i]种排序中逆序数的和为cal[n-i]了,还要加上在i之前的序列的逆序数之和和[1,i)对[i,n]产生的逆序数,还有在替换第i个数的时候,替换后的a[i]产生的逆序数

好难解释啊。。。。。不过应该不是很难推出来!!!!体会一下思路。
然后线段树真的不能开两倍啊喂!!!然后杭电真的不支持long long 啊喂!
标准的线段树应该开4N+100。

#include <stdio.h>
#include <iostream>
using namespace std;
#define mod 1000000007
#define llt long long
llt cal[110],a[110],A[110];
llt tree[330];
template<class T>
inline char read(T &n){
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' | c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return c;
}
template <class T>
inline void write(T n) {
    if(n < 0) {
        putchar('-');
        n = -n;
    }
    int len = 0,data[20];
    while(n) {
        data[len++] = n%10;
        n /= 10;
    }
    if(!len) data[len++] = 0;
    while(len--) putchar(data[len]+48);
}

void create(llt l,llt r,llt rt)
{
    tree[rt]=0;
    if(l==r) return;
    llt mid=(l+r)>>1;
    create(l,mid,rt<<1);
    create(mid+1,r,rt<<1|1);
}
llt query(llt ll,llt rr,llt l,llt r,llt rt)
{
    if(l==ll&&r==rr) return tree[rt];
    llt mid=(l+r)>>1;
    if(rr<=mid) return query(ll,rr,l,mid,rt<<1);
    else if(ll>mid) return query(ll,rr,mid+1,r,rt<<1|1);
    else
    {
        llt ans=query(ll,mid,l,mid,rt<<1);
        ans+=query(mid+1,rr,mid+1,r,rt<<1|1);
        return ans;
    }
}
void update(llt l,llt r,llt rt,llt x)
{
    if(l==x&&r==x)
    {
        tree[rt]++;
        return;
    }
    llt mid=(l+r)>>1;
    if(x<=mid) update(l,mid,rt<<1,x);
    else update(mid+1,r,rt<<1|1,x);
    tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void init()
{
    cal[0]=0,cal[1]=0,cal[2]=1;
    A[1]=1;A[0]=1;
    for(int i=2;i<=100;i++)
    {A[i]=(A[i-1]*i)%mod;
    }

    for(int i=3;i<=100;i++)
    {
        cal[i]=((i*cal[i-1])%mod+(i*(i-1)*A[i-1]/2)%mod)%mod;
    }
}
llt sum(llt x)
{
    return ((x-1)*x)/2;
}
int main()
{
    init();llt n;
    while(scanf("%I64d",&n)!=EOF)
    {
        llt ans=0;
        llt i,j,pre=0,tmp=0;
        llt k;
        create(1,100,1);
        for(i=1;i<=n;i++)
        {
            read(a[i]);
            tmp=query(a[i]+1>100?100:a[i]+1,100,1,100,1);
            j=n-i-(n-a[i]-tmp);  //比a[i]小的个数
            if(j<=0) continue;
            k=A[n-i];llt p=cal[n-i];
            ans=(ans+((p*j)%mod+(pre*k*j)%mod+(sum(j)*k)%mod)%mod)%mod;
            update(1,100,1,a[i]);
            pre+=j;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值