看程序写结果(program)
Time Limit:1000ms Memory Limit:64MB
题目描述
LYK最近在准备NOIP2017的初赛,它最不擅长的就是看程序写结果了,因此它拼命地在练习。
这次它拿到这样的一个程序:
Pascal:
readln(n);
for i:=1 to n do read(a[i]);
for i:=1 to n do for j:=1 to n do for k:=1 to n do for l:=1 to n do
if (a[i]=a[j]) and (a[i] < a[k]) and (a[k]=a[l]) then ans:=(ans+1) mod 1000000007;
writeln(ans);
C++:
pcanf(“%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
输出样例
4
数据范围
对于20%的数据n<=50。
对于40%的数据n<=200。
对于60%的数据n<=2000。
对于100%的数据n<=100000,1<=ai<=1000000000。
其中均匀分布着50%的数据不同的ai个数<=10,对于另外50%的数据不同的ai个数>=n/10。
思路,其实就是任选两个相等的数,再任选两个相同的数,统计有多少个方案前面的数<后面的。(可以选相同的数,1,2–2,1 )也算不同的方案
先排序
F[i]表示1-i中选相同的数不同组合的方案有几种
然后倒着扫(确保>),求个个有多少个相同的,跟前面的所有方案乘一下就行了
#include <iostream>
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
ll f[100005],a[100005];
const int mod=1e9+7;
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
ll sum=1;
f[1]=1;
sort(a+1,a+n+1);
for (int i=2; i<=n; i++)
{
f[i]=f[i-1];
if (a[i]==a[i-1])
{
f[i]=f[i]-1ll*sum*sum;
sum++;
f[i]=f[i]+1ll*sum*sum;
f[i]%=mod;
} else sum=1,f[i]++;
}
ll ans=0;
sum=1;
for(int i=n-1;i>=1;i--)
{
if(a[i]==a[i+1])
sum++;
else
{
ans=(ans+sum*sum*f[i])%mod;
sum=1;
}
}
printf("%lld\n",ans);
}