Test 4 for NOIP- Result for Day1

来源:互联网 发布:软件破解安卓 编辑:程序博客网 时间:2024/05/21 20:22

头大

这个暑假完就要去搞NOIP了。。。

暑假55天也就20次测试。。。为防万一我还是每次测试玩都写个总结。。


。。。我收回Test 3总结报告的话。。。我考完这次真的连怎么说自己都不知道怎么说了。。。被long=int+int阴了70分(否则应该是110)
问题是还是原题。。。。。。

Day1 (60/300)

T1 Math(30/100)

题目背景
SOURCE:NOIP2015-SHY-3

题目描述
给定 2 个数组 a[] 和 b[] ,他们有相同的长度 n ,你可以任意对 a[] 和 b[] 进行重排列,我们定义函数
x = Σ(a[i]*b[i])
请问 x 最大可以取到多少,最小可以取到多少?

输入格式
第一行一个数字 n ,表示数组的长度;
第二行 n 个整数,表示数组 a ;
第三行 n 个整数,表示数组 b 。

输出格式
输出两个整数表示答案。

样例数据 1
输入  [复制]

2
10 3
10 9
输出

127 120
备注
【样例说明】
Maximum:10 * 10 + 3 * 9 = 127
Minimum:10 * 3 + 10 * 9 = 120

【数据范围】
对 40% 的输入数据 :n≤10
对 100% 的输入数据 :n≤100000,1≤a[i], b[i]≤100000

本来用一个什么什么定理就能搞定的,代码极短而且还不需要用高精度,最后因为没有ans = (long long) a[i]*b[i]就gg了。。。
无语。

STD.CPP

#include<iostream>#include<iomanip>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<string>#include<cstring>#include<ctime>using namespace std;int n,a[100500],b[100500];unsigned long long maxx=0,minn=0;int main(){    cin >> n;    for(int i=1;i<=n;i++)   cin >> a[i];    sort(a+1,a+n+1);    for(int i=1;i<=n;i++)   cin >> b[i];    sort(b+1,b+n+1);        for(int i=1;i<=n;i++)    {        maxx += (long long)a[i]*b[i];        minn += (long long)a[n-i+1]*b[i];    }    cout << maxx << " " << minn << endl;    return 0;}

T2 Shortest(30/100)

题目背景
SOURCE:NOIP2015-SHY-3

题目描述
给定一张 n 个点的有向带权完全图,和一个数组 a[] ,请按顺序删除数组中的点,请求出在删除点 a[i] 以前,所有未删除点对之间的最短路的值的和。

输入格式
第一行一个整数 n ,表示点数;
接下来 n 行,每行 n 个数构成邻接矩阵,描述每条边的权值,保证 i 号点到 i 号点的权值为 0 ;
最后一行 n 个小于等于 n 的不同的数,描述数组 a[]。

输出格式
输出 1 行 n 个数,表示答案。

样例数据 1
输入  [复制]

4
0 3 1 1
6 0 400 1
2 4 0 1
1 1 1 0
4 1 2 3
输出

17 23 404 0
备注
【数据范围】
对 30% 的输入数据 :1≤n≤10 ;
对 100% 的输入数据 :1≤n≤500;0<权值≤100000 。

MY.CPP

#include<iostream>#include<iomanip>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<string>#include<cstring>#include<ctime>using namespace std;int u,v,ai[505];long long ans[505];long long mar[505][505];bool visit[505];int n,tot=0,first[505],p[505];long long dis[505];bool exist[505];struct node{    int x;    int y;    long long w;    int next;}side[250050];void addedge(int x,int y,long long w)//建立邻接表(数组方式){    side[++tot].x=x;    side[tot].y=y;    side[tot].w=w;    side[tot].next=first[x];    first[x]=tot;}long long spfa(int s,int t) //主程序,SPFA{    memset(exist,0,sizeof(exist));    memset(dis,127,sizeof(dis));    //初始化最短距离为一个较大的值    int head=0,tail=1;                       //头指针,尾指针     dis[s]=0;                            //起点的最短距离赋值为0    p[1]=s;                              //起点t入队    exist[s]=true;                       //做入队标记    while(head<tail)    {        head++;        exist[p[head]]=false;        for(int u=first[p[head]];u!=0;u=side[u].next)        {            #define i1  (dis[p[head]]+side[u].w)            #define i2  (dis[side[u].y])            if(i1 < i2)                  //如果能更新终点的最短路            {                i2 = i1;                 //则更新该终点的最短路                if(!exist[side[u].y])    //如果该终点不在队列中                {                    tail++;                 //队尾指针递增                    p[tail]=side[u].y;      //把更新了最短路的终点v[u]入队                    exist[side[u].y]=true;  //作入队标记                }            }        }    }    return dis[t];}int main(){    memset(ans,0,sizeof(ans));    cin >> n;    for(int i=1;i<=n;i++)      for(int j=1;j<=n;j++)        cin >> mar[i][j];    for(int i=n;i>=1;i--)        cin >> ai[i];    for(int i=1;i<=n;i++)    {        visit[ai[i]] = true;        for(int j=1;j<=i;j++)          {            addedge(ai[i],ai[j],mar[ai[i]][ai[j]]);            addedge(ai[j],ai[i],mar[ai[j]][ai[i]]);          }        for(int a=1;a<=i;a++)          for(int b=1;b<=i;b++)            ans[n-i+1] += spfa(ai[a],ai[b]);        }    for(int i=1;i<=n;i++) cout << ans[i] << " ";}

这道题告诉我们:不要因为你鄙视Floyed的复杂度而抛弃它选Dijkstra或者因纯粹的爱国心两者都扔而去选SPFA。实践证明考虑选择求最短路的模板时应该遵循先F再D后S的顺序,除非题目给的图是和八爪鱼一样的放射形才首选S(SPFA求链的最短路很快)
于是我就GG了。orz

STD.CPP

//卧槽是Floyed#include<iostream>#include<iomanip>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<string>#include<cstring>#include<ctime>using namespace std;int n;long long  a[505];long long  f[505][505],ans[505];int main() {    cin >> n;    for(int i=1;i<=n;i++)      for(int j=1;j<=n;j++)        cin >> f[i][j];    for(int i=1;i<=n;i++)        cin >> a[i];    for(int i=n;i>=1;i--)    {        for(int j=n;j>i;j--)          for(int k=n;k>i;k--)          {            f[a[i]][a[j]] = min(f[a[i]][a[j]],f[a[i]][a[k]]+f[a[k]][a[j]]);            f[a[j]][a[i]] = min(f[a[j]][a[i]],f[a[j]][a[k]]+f[a[k]][a[i]]);          }        for(int j=n;j>i;j--)          for(int k=n;k>i;k--)            f[a[j]][a[k]] = min(f[a[j]][a[k]],f[a[j]][a[i]]+f[a[i]][a[k]]);        for(int j=n;j>=i;j--)          for(int k=n;k>=i;k--)            ans[i] += f[a[j]][a[k]];    }    for(int i=1;i<=n;i++)   cout << ans[i] << " ";}

3.Half(0/100)

题目背景
SOURCE:NOIP2015-SHY-1

题目描述
给定 n 个数,求最大的数 m ,使得 m 是 n 个数中至少一半的数的约数。
注意:m 不一定在 n 个数中,只要满足要求即可。

输入格式
第一行一个整数 n ,表示数组大小。
第二行 n 个整数,表示数组的 n 个元素。

输出格式
输出一个整数,表示答案。

样例数据 1
输入  [复制]

6
6 2 3 4 5 6
输出

3
备注
【样例说明】
3 是 6、3、6 的约数,达到了一半的要求;

【数据范围】
对 40% 的输入数据 : n≤100;
对 100% 的输入数据 :n≤100000;1≤数字的大小≤10^12。

奇特的gcd与随机枚举,我还要找时间研究研究。

STD.CPP

#include<iostream>#include<iomanip>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<string>#include<cstring>#include<ctime>using namespace std;int n,cnt;long long a[1000001],c[1000001],v[1000001],f[1000001];long long gcd(long long a,long long b){    if(!b)  return a;    return gcd(b,a%b);}int find(int n,long long aim){    if(v[n]==aim)   return n;    int left=0,right=n,mid=(left+right)>>1;    for(;left+1<right;mid=(left+right)>>1)      if(v[mid]<aim)    left=mid;      else  right=mid;    return right;}int main(){    cin >> n;    for(int i=1;i<=n;i++)           cin >> a[i];    srand(time(0)); random_shuffle(a+1,a+n+1);    long long ans = 0;    for(int i=1;i<=n&&i<=10;i++)    {        cnt = 0;        sort(c+1,c+cnt+1);        int num=0;        for(long long j=1;j*j<=a[i];j++)            if(!(a[i]%j))            {                v[++num]=j; f[num]=0;                if(j*j!=a[i])                {                    v[++num] = a[i]/j;                    f[num] = 0;                }            }        sort(v+1,v+num+1);        for(int j=1;j<=n;j++)            ++f[find(num,gcd(a[i],a[j]))];        for(int j=1;j<=num;j++)        {            long long total = 0;            if(v[j]<=ans)   continue;            for(int k=j;k<=num;k++)                if(!(v[k]%v[j]))    total+=f[k];            if(total*2>=n)  ans = max(ans,v[j]);        }    }    cout << ans << endl;}

代码一样短的吓人。。而且我一直以为不可能在我考完noip前会出现的随机大法就这样出现了。
想死的心都没了。

原创粉丝点击