看程序写结果(program)
Time Limit:1000ms Memory Limit:64MB
题目描述
LYK 最近在准备 NOIP2017 的初赛,它最不擅长的就是看程序写结果了,因此它拼命地
在练习。
这次它拿到这样的一个程序:
scanf(“%d”,&n);
for (i=1; i<=n; i++) scanf(“%d”,&a[i]);
for (i=1; i<=n; i++)
for (j=1; j<=n; j++)
for (k=1; k<=n; k++)
for (l=1; l<=n; l++)
if (a[i]==a[j] && a[i]< a[k] && a[k]==a[l])
ans=(ans+1)%1000000007;
printf(“%d\n”,ans);
LYK 知道了所有输入数据,它想知道这个程序运行下来会输出多少。
输入格式(program.in)
第一行一个数 n,第二行 n 个数,表示 ai。
输出格式(program.out)
一个数表示答案。
输入样例
4
1 1 3 3
输出样例
16
数据范围
对于 20%的数据 n<=50。 对于 40%的数据 n<=200。 对于 60%的数据 n<=2000。
对于 100%的数据 n<=100000,1<=ai<=1000000000。
其中均匀分布着 50%的数据不同的 ai 个数<=10,对于另外 50%的数据不同的 ai 个
数>=n/10。
一种数的选择方案有num^2种,因为可以选同一个数,所以就相当于在两个num长的数组中一边任选一个。
那么我们用f[i]表示1~i 这一段数中选两个数作为形式A=A< B=B中A的方案数。
例如 1 1 1 2 3 3
对应的f[]数组为 1 4 9 10 11 14
我们先将a数组升序排列,然后求出f[]数组,然后从n->1,把每一种数的个数与前面的f[]相乘,即为当前这种数作为B时对答案的贡献。
看代码有助于理解:
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define LL long long
const int MOD=1000000007;
using namespace std;
int n,a[100009];
LL f[100009],ans;
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+n+1);
LL num=1;f[1]=1;
for(int i=2;i<=n;i++)
{
f[i]=f[i-1];
if(a[i]==a[i-1])
{
f[i]=(f[i]+1ll*2*num+1);
num++;
}
else
{
f[i]+=1;
num=1;
}
}
//for(int i=1;i<=n;i++) printf("%lld ",f[i]);puts("");
num=1;
for(int i=n-1;i>=1;i--)
{
if(a[i]==a[i+1]) num++;
if(a[i]!=a[i+1])
{
ans=(ans+f[i]*(num*num%MOD))%MOD;
num=1;
}
}
printf("%lld",ans);
return 0;
}