第十六届上海大学程序设计联赛春季赛

上海高校金马五校赛

Posted by Zexin Zhang on April 18, 2018

题目

NowCode Original Link

A Wasserstein Distance

最近对抗生成网络(GAN)很火,其中有一种变体WGAN,引入了一种新的距离来提高生成图片的质量。这个距离就是Wasserstein距离,又名铲土距离。 这个问题可以描述如下:

有两堆泥土,每一堆有n个位置,标号从1~n。第一堆泥土的第i个位置有ai克泥土,第二堆泥土的第i个位置有bi克泥土。小埃可以在第一堆泥土中任意移挪动泥土,具体地从第i个位置移动k克泥土到第j个位置,但是会消耗的体力。小埃的最终目的是通过在第一堆中挪动泥土,使得第一堆泥土最终的形态和第二堆相同,也就是ai=bi (1<=i<=n), 但是要求所花费的体力最小

左图为第一堆泥土的初始形态,右图为第二堆泥土的初始形态,颜色代表了一种可行的移动方案,使得第一堆泥土的形态变成第二堆泥土的形态

#include <bits/stdc++.h>

using namespace std;
int main() {
    //freopen("inputlx.txt","r",stdin);

    int t=0,n=0;
    long long ans=0;
    int a[100010],b[100010],c[100010];
    scanf("%d",&t);
    while(t--) {
        scanf("%d",&n);
        ans=0;
        for(int i=1; i<=n; i++) {
            scanf("%d",&a[i]);
        }
        for(int i=1; i<=n; i++) {
            scanf("%d",&b[i]);
        }
        for(int i=1; i<=n; i++) {
            c[i]=a[i]-b[i];
        }
        for(int i=1; i<=n-1; i++) {
            if(c[i] > 0 && c[i] != 0) {
                ans+=c[i];
                c[i+1]+=c[i];
                c[i] = 0;
            }
            if (c[i] < 0 && c[i] != 0) {
                ans-=c[i];
                c[i+1]+=c[i];
                c[i]=0;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

E 小Y吃苹果

小Y买了很多苹果,但他很贪吃,过了几天一下就吃剩一只了。每一天小Y会数出自己的苹果个数X,如果X是偶数,他就会吃掉只苹果;如果X是奇数,他就会吃掉只苹果。

你知道现在苹果只剩下一只,并且小Y是在N天前买的苹果,现在小Y想知道在那天买了多少苹果。当然,可能性不止一种,你只需要求出他买的苹果数量有多少种可能。

#include <bits/stdc++.h>

using namespace std;
int main(){
    freopen("inputlx.txt", "r", stdin);
    long long n=0,ans=0;
    scanf("%lld",&n);
    ans=pow(2,n);
    printf("%lld",ans);
}

F 1 + 2 = 3?

小Y在研究数字的时候,发现了一个神奇的等式方程,他屈指算了一下有很多正整数x满足这个等式,比如1和2,现在问题来了,他想知道从小到大第N个满足这个等式的正整数,请你用程序帮他计算一下。 (表示按位异或运算)

#include <bits/stdc++.h>

using namespace std;
long long  a[100],tot[100];

int main(){
    memset(a, 0, sizeof(a));
    memset(tot, 0, sizeof(tot));
    a[1]=1;a[2]=1;a[3]=2;tot[1]=1;tot[2]=2;tot[3]=4;
    for(int i=3;i<=99;i++){
        a[i]=a[i-1]+a[i-2];
        tot[i]=tot[i-1]+a[i];
    }
   // printf("a[99]%lld\n",a[60]);

    freopen("inputlx.txt","r",stdin);
    long long t,n,ans,temp,t1,j;
    bitset<64> b;
    scanf("%lld", &t);
    while(t--){
        b.reset();
        scanf("%lld",&n);
        for (int i = 1; i <= 99; i++)
        {
            if (tot[i]>=n&&tot[i-1]<n){
                b.flip(i-1);
                temp=i-1;
                goto loop;
                int x = max(1,2);
            }
        }
        loop:
        unsigned long long ans=b.to_ullong();
        ans=ans+(n-temp-1);
        printf("%lld\n",ans);
    }
}

L K序数

给一个数组 a,长度为 n,若某个子序列中的和为 K 的倍数,那么这个序列被称为“K 序列”。现在要你 对数组 a 求出最长的子序列的长度,满足这个序列是 K 序列。 

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

ll p[100005];

int r(ll n, ll k)
{
    int sum = 0;
    for (ll i = 0; i < n; i++)
    {
        sum += p[i];
        sum = sum % k;
    }
    if (sum % k == 0)
    {
        return n;
    }
    for (ll i = n - 1; i > 0; i--)
    {
        sum = 0;
        for (ll ii = 0; ii < i; ii++)
        {
            sum += p[ii];
            sum = sum % k;
        }
        if (sum % k == 0)
            return i;
        for (ll j = 0; j < n - i; j++)
        {
            sum = sum - p[j] + p[j + i];
            sum = sum % k;
            if (sum % k == 0)
                return i;
        }
    }
    return 0;
}

int main()
{
    ll n, k;
    //freopen("inputlx.txt","r",stdin);

    while (cin >> n)
    {
        cin >> k;
        memset(p, 0, sizeof(p));
        for (ll i = 0; i < n; i++)
        {
            cin >> p[i];
        }
        cout << r(n, k) << endl;
    }
    return 0;
}

I 二数

我们把十进制下每一位都是偶数的数字叫做“二数”。 小埃表示自己很聪明,最近他不仅能够从小数到大:2,3,4,5….,也学会了从大数到小:100,99,98…,他想知道从一个数开始数最少的数就得到一个二数。但是聪明的小森已经偷偷在心里算好了小埃会数到哪个二数,请你求出他要数到哪个数吧。 换句话说,给定一个十进制下最多105位的数字,请你求出和这个数字的差的绝对值最小的二数,若答案不唯一,输出最小的那个。 也就是说,给定数字n,求出m,使得abs(n-m)最小且m[i] mod 2 = 0

#include <bits/stdc++.h>

using namespace std;
int main(){
    int t;
    char num[100010],ans[100010];
    scanf("%d",&t);
    while(t--){
        memset(num, '\0', sizeof(num));
        memset(ans, '\0', sizeof(ans));
        scanf("%s",num);
        int len=strlen(num);
        if(len>=2){
            
                if((num[len-1]-'0')%2!=0){
                    if((num[len-2]-'0')>=5)
                    num[len-1]=num[len-1]+'1';
                    for(int i=len-2;i<=0;i++){
                        num[]
                    }
                }
        }
        if(len==1){

        }
    }
}