第一题,给你一个矩形的面积,求矩形的最小周长。
可知,当两边长最接近的时候,周长最小。所以可以从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
在枚举的时候可以把序列分成三部分。
通过统计可以得到比对到第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;
}