• CONTEST199 [有奖]洛谷8月月赛题解


    http://www.luogu.org/contest/show?tid=199

    T1: 集合求和

    可以找一下规律,对于一个包含n个元素的集合,每个元素在所有子集中出现的次数均为2^(n-1),将sum乘这个数即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #define ll long long
    using namespace std;
    ll x,s,sum;
    int main()
    {
        s=1;
        while (cin>>x) {sum+=x; s<<=1;};
        printf("%lld",sum*(s>>1));
        return 0;
    }

    T2: GCD SUM

    我们可以用f[i]表示gcd(x,y)=i的数对共有f[i]个。

    从n->1枚举,首先将f[i]赋值为(n/i)*(n/i),然后去掉f[2*i],f[3*i]....即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #define ll long long
    using namespace std;
    int n;
    ll ans,f[100005];
    int main()
    {
        scanf("%d",&n);
        for (int d=n;d>=1;d--)
        {
            f[d]=1ll*(1ll*n/d)*(n/d);
            for (int i=d+d;i<=n;i+=d) f[d]-=f[i];
            ans+=f[d]*d;
        }
        printf("%lld",ans);
    }

    T3: 看球泡妹子

    本着骗分的想法写了个很暴力的dp,f[i][j][k]即前i个比赛选j个目前帅哥值为k,答案即为max{f[m][k][i],c<=i<=sum},特判一下如果最大的k项相加仍<c则无解(否则只有90分)。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #define ll long long
    using namespace std;
    int n,m,mx,mn,c,sum,ans;
    int a[105],b[105],p[105],q[105],s[105];
    int f[105][105][2005];
    inline int read()
    {
        int a=0,f=1; char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
        while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
        return a*f;
    }
    inline bool cmp(int a,int b)
    {
        return a>b;
    }
    int main()
    {
        n=read(); m=read(); mx=read(); c=read(); 
        for (int i=1;i<=n;i++) a[i]=read();
        for (int i=1;i<=n;i++) b[i]=read();
        for (int i=1;i<=m;i++) p[i]=read(),q[i]=read(),s[i]=b[p[i]]+b[q[i]];
        sort(s+1,s+m+1,cmp);
        for (int i=1;i<=mx;i++) sum+=s[i];
        if (sum<c) {printf("-1"); return 0;}
        for (int i=1;i<=m;i++)
            for (int j=1;j<=mx;j++)
                for (int k=mn;k<=2000;k++)
                {
                    f[i][j][k]=f[i-1][j][k];
                    if (k-b[p[i]]-b[q[i]]>=0) f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k-b[p[i]]-b[q[i]]]+a[p[i]]*a[q[i]]);
                }
        for (int i=c;i<=2000;i++) ans=max(ans,f[m][mx][i]);
        if (!ans) printf("-1"); else printf("%d",ans);
        return 0;
    }

    T3第二种方法:

    令x[i]=20-(b[p[i]]+b[q[i]]),y[i]=a[p[i]]*a[q[i]].那么若满足题意就等价于满足sigma(x[i])<20*k-c;这就成了一个二维费用背包。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    int n,m,K,c,ans;
    int a[105],b[105],p[105],q[105],x[105],y[105];
    int f[105][2005];
    inline int read()
    {
        int a=0,f=1; char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
        while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
        return a*f;
    }
    int main()
    {
        n=read(); m=read(); K=read(); c=read(); c=20*K-c;
        for (int i=1;i<=n;i++) a[i]=read();
        for (int i=1;i<=n;i++) b[i]=read();
        for (int i=1;i<=m;i++) {p[i]=read(); q[i]=read(); x[i]=20-b[p[i]]-b[q[i]]; y[i]=a[p[i]]*a[q[i]];}
        for (int i=1;i<=m;i++)
            for (int j=K;j>=1;j--)
                for (int k=c;k>=x[i];k--) f[j][k]=max(f[j][k],f[j-1][k-x[i]]+y[i]);
        for (int i=1;i<=c;i++) ans=max(ans,f[K][i]);
        if (!ans) printf("-1"); else printf("%d",ans);
        return 0;
    }

    T4: 电路维修

    应该是这次比赛比较难的一道题了,我们可以对每条边所在格的四个顶点连边,已相连的权值为0,未相连的权值为1。然后跑最短路就好。

    PS:对于判断无解,则为n+m为奇数,画个图即可发现。

    PS:我们可以发现有一些点是无论如何都不会走到的,可以忽略这些点,可以省去一半。

    PS:spfa80分会TLE,heap+priority_queue可过。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define ll long long
    #define INF 1000000000
    #define M 300005
    #define pa pair<ll,int>
    using namespace std;
    int n,m,cnt;
    int head[300000],q[300010],dis[300000],next[1200000],list[1200000],key[1200000];
    bool v[300000],vis[300000];
    priority_queue<pa,vector<pa>,greater<pa> >qq;
    inline int read()
    {
        int a=0,f=1; char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
        while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
        return a*f;
    }
    inline void insert(int x,int y,int z)
    {
        next[++cnt]=head[x];
        head[x]=cnt;
        list[cnt]=y;
        key[cnt]=z;
    }
    /*inline int spfa()
    {
        for (int i=1;i<=n*m;i++) {dis[i]=INF; v[i]=0;}
        int t=0,w=1,x; dis[1]=0; v[1]=1; q[1]=1;
        while (t!=w)
        {
            t=(t+1)%M;
            x=q[t];
            for (int i=head[x];i;i=next[i])
                if (dis[list[i]]>dis[x]+key[i])
                {
                    dis[list[i]]=dis[x]+key[i];
                    if (!v[list[i]])
                    {
                        v[list[i]]=1;
                        w=(w+1)%M;
                        q[w]=list[i];
                    }
                }
            v[x]=0;
        }
        return dis[n*m];
    }*/
    inline int dijkstra()
    {
        for(int i=1;i<=m*n;i++)dis[i]=INF;dis[1]=0;
        memset(vis,0,sizeof(vis));
        qq.push(make_pair(0,1));
        while(!qq.empty())
        {
            int now=qq.top().second;qq.pop();
            if(vis[now])continue;vis[now]=1;
            for(int i=head[now];i;i=next[i])
                if(dis[now]+key[i]<dis[list[i]])
                {
                    dis[list[i]]=dis[now]+key[i];
                    qq.push(make_pair(dis[list[i]],list[i]));
                }
        }
        return dis[n*m];
    }
    int main()
    {
        int t=read();
        while (t--)
        {
            n=read()+1; m=read()+1;
            if ((n+m)%2==1) {puts("NO SOLUTION"); continue;}
            for (int i=1;i<n;i++)
            {
                char c[505];
                scanf("%s",c+1);
                if (i%2==1)
                {
                    for (int j=1;j<m;j+=2)
                    {
                        if (c[j]!='/') {insert((i-1)*m+j,i*m+j+1,0); insert(i*m+j+1,(i-1)*m+j,0);}
                        else {insert((i-1)*m+j,i*m+j+1,1); insert(i*m+j+1,(i-1)*m+j,1);}
                    }
                    for (int j=2;j<m;j+=2)
                    {
                        if (c[j]!='/') {insert(i*m+j,(i-1)*m+j+1,1); insert((i-1)*m+j+1,i*m+j,1);}
                        else {insert(i*m+j,(i-1)*m+j+1,0); insert((i-1)*m+j+1,i*m+j,0);}
                    }
                }
                if (i%2==0)
                {
                    for (int j=1;j<m;j+=2)
                    {
                        if (c[j]!='/') {insert(i*m+j,(i-1)*m+j+1,1); insert((i-1)*m+j+1,i*m+j,1);}
                        else {insert(i*m+j,(i-1)*m+j+1,0); insert((i-1)*m+j+1,i*m+j,0);}
                    }
                    for (int j=2;j<m;j+=2)
                    {
                        if (c[j]!='/') {insert((i-1)*m+j,i*m+j+1,0); insert(i*m+j+1,(i-1)*m+j,0);}
                        else {insert((i-1)*m+j,i*m+j+1,1); insert(i*m+j+1,(i-1)*m+j,1);}
                    }
                }
            }
            printf("%d
    ",dijkstra());
            for (int i=1;i<=n*m;i++) head[i]=0; cnt=0;
        }
        return 0;
    }

    第一次AK……纪念一下。

  • 相关阅读:
    需要返回对象时候,不要以引用形式返回
    成对使用new和delete,传值传引用
    赋值重载的约定(1)
    oracle操作字符串:拼接、替换、截取、查找
    Oracle CASE WHEN 用法介绍
    oracle中如何对字符串进行去除空格的方法
    日期显示
    Oracle Cursor用法总结
    每天一个linux命令(26):用SecureCRT来上传和下载文件
    每天一个linux命令(25):linux文件属性详解
  • 原文地址:https://www.cnblogs.com/ws-fqk/p/4735123.html
Copyright © 2020-2023  润新知