现在的位置: 首页 > 综合 > 正文

4周周赛解题报告

2019年02月28日 ⁄ 综合 ⁄ 共 2404字 ⁄ 字号 评论关闭

烦躁,不搞了,直接写报告了。

第一题,水题,意思很好理解,细节需要注意,然后,然后就没有然后了。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
    int n,k,a[100005],sum;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        sum=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]<0&&k>0)
            {
                a[i]=-a[i];
                k--;
            }
        }
        sort(a,a+n);
        if(k%2==1)a[0]=-a[0];
        for(int i=0;i<n;i++)sum+=a[i];
        cout<<sum<<endl;
    }
    return 0;
}

第二题,买东西的问题,一开始思路其实对的,由于代码风格什么的原因,各种没a。

就是挑最小的购物方案,从大往小遍历一遍,每逢那么多个后面两个不及价格就好了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
bool cmp(int a,int b){return a>b;}
int main()
{
    int m,q,mi,n,a[100005],v,sum;
    while(scanf("%d",&m)!=EOF)
    {
        mi=100005;
        for(int i=0;i<m;i++)
        {
            scanf("%d",&q);
            if(q<mi)mi=q;
        }
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
        }
        sort(a,a+n,cmp);
        v=0;
        sum=0;
        for(int i=0;i<n;i++)
        {
            if(v<0)
            {
                v++;
            }
            else if(v==mi)
            {
                v=-1;
            }
            else
            {
                sum+=a[i];
                v++;
            }
        }
        cout<<sum<<endl;
    }
    return 0;
}

第三题,神dp。

设f[i][j][k]数组代表j个人总和为i,下一个坐不进的人是k的情况的多少。之后就判断可不可能,然后再排列组合一下。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
double f[55][55][55];//f[i][j][k],j people sum is i ,k the next
int n,a[55],p;
double  sum,c[55];
int main()
{
    c[0]=1;
    for(int i=1; i<=50; i++)c[i]=c[i-1]*i;
    while(scanf("%d",&n)!=EOF)
    {
        memset(f,0,sizeof(f));
        sum=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];
            f[0][0][i]=1;
        }
        scanf("%d",&p);
        if(sum<=p)
        {
            cout<<n<<endl;
            continue;
        }
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                if(j!=i)
                {
                    for(int g=n; g>=1; g--)
                    {
                        for(int k=p; k>=a[i]; k--)
                        {
                            f[k][g][j]+=f[k-a[i]][g-1][j];
                        }
                    }
                }
            }
        }
        sum=0;
        for(int i=1; i<=n; i++)
        {
            for(int g=1; g<=n; g++)
            {
                if(a[i]>p)a[i]=p+1;
                for(int j=p-a[i]+1; j<=p; j++)
                    sum+=f[j][g][i]*c[g]*c[n-g-1]*g;
            }
        }
        sum/=c[n];
        printf("%.9f\n",sum);
    }
    return 0;
}

第四题,看懂题就能过,略过。

下俩题不说了,搞不动了,。。。。。。。

第七题,水模拟,不解释了。

第八题,略有技巧,先从左往右遍历,遇r输出编号,再从右往左,遇l输出编号,ok了

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int main()
{
    string s;
    int l;
    while(cin>>s)
    {
        l=s.length();
        for(int i=0;i<l;i++)
        {
            if(s[i]=='r')printf("%d\n",i+1);
        }
        for(int i=l-1;i>=0;i--)
        {
            if(s[i]=='l')printf("%d\n",i+1);
        }
    }
    return 0;
}

最后一题,也是神dp,好题啊,感觉和北航校赛的某题一样的。一开始按照最长升序列(LIS)的方法来,果断超时,不过LIS有二分的做法,这题不适用。网上看到神代码之后,顿悟,下面是神代码及我自己写的注释。

#include <cstdio>
#include <algorithm>
using namespace std;
const int MX=100000;
int n,i,j,a[MX+10],r[MX+10],b,x,res=1;
int main() {
  for (i=2; i<=MX; i++) if (a[i]==0) for (j=i; j<=MX; j+=i) a[j]=i;//标记j的最大质数约数
  scanf("%d",&n);
  for (i=0; i<n; i++) {
    scanf("%d",&b);
    x=0;
    for ( j=b; j>1; j/=a[j]) x=max(x,r[a[j]]);//找到b的质约数所在最高阶
    for (j=b; j>1; j/=a[j]) r[a[j]]=max(r[a[j]],x+1);//更新这些约数所在阶
    res=max(res,x+1);//更新最大阶数
  }
  printf("%d\n",res);
  return 0;
}

抱歉!评论已关闭.