埃森哲杯第十六届上海大学程序设计联赛春季赛暨上海高校金马五校赛

链接:https://www.nowcoder.com/acm/contest/91/A
来源:牛客网

Wasserstein Distance
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

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


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

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


输入描述:

输入测试组数T,每组测试数据,第一行输入n,1<=n<=100000,紧接着输入两行,每行n个整数,前一行为a
1
, a
2
,…,a
n
,后一行为b
1
,b
2
,…,b
n
.其中0<=a
i
,b
i
<=100000,1<=i<=n,数据保证 

输出描述:

对于每组数据,输出一行,将a土堆的形态变成b土堆的形态所需要花费的最小体力
示例1

输入

2
3
0 0 9
0 2 7
3
1 7 6
6 6 2

输出

2
9

备注:

输入数据量较大,建议使用scanf/printf

这个你凑出样例就行了,分一下情况,贪心处理

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        int a[100005],b;
        ll sum=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&b);
            if(a[i]!=b)
            {
                if(a[i]>b)
                {
                    sum+=(a[i]-b)*1LL;
                    a[i+1]+=a[i]-b;
                }
                else if(a[i]<b)
                {
                    sum+=(b-a[i])*1LL;
                    a[i+1]-=b-a[i];
                }
            }
        }
        printf("%lld\n",sum);
    }
    return 0;
}

链接:https://www.nowcoder.com/acm/contest/91/D
来源:牛客网

数字游戏
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

小埃和小森在玩一个数字游戏,小埃先从区间[L1, R1]里选择1个数字n1,小森看到小埃选的数字后,从[L2,R2]里选择1个数字n2, 将n1和n2连接在一起(n1在前, n2在后),形成一个新的数字,若这个数字可以被mod整除,那么小森获胜,否则小埃获胜。若两个人均采取最优策略,试问谁获胜?

输入描述:

输入测试组数T,每组数据,输入一行整数L1, R1, L2, R2, mod,其中1<=L1<=R1<109,1<=L2<=R2<109, 1<=mod<=106

输出描述:

每组数据输出一行,若小埃获胜,输出WIN,否则输出LOSE
示例1

输入

2
6 9 3 5 1
5 10 7 8 6

输出

LOSE
WIN

学弟玄学AC,但是我认为中间我们的代码是对的,但是一直超时啊

这份代码区间并没有分完,但是可以过?

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int a[maxn];
int pf(int x)
{
    int s=1;
    for(int i=0;i<x;i++)
        s*=10;
    return s;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        memset(a,0,sizeof a);
        int L1,R1,L2,R2,m;
        cin>>L1>>R1>>L2>>R2>>m;
        if(R1-L1+1>=m)
        {
            fill(a,a+m,1);
        }
        else
        {
            if(L1%m<=R1%m)
            {
                for(int i=L1%m;i<=R1%m;i++)
                    a[i]=1;
            }
            else
            {
                for(int i=0;i<=R1%m;i++)
                    a[i]=1;
                for(int i=L1%m;i<m;i++)
                    a[i]=1;
            }
        }
        int t=0,x=L2;
        if(x==0) t=1;
        while(x)
        {
            x/=10;
            t++;
        }
        int l=pf(t);
        int f=0;
        for(int i=0;i<m;i++)
        {
            if(a[i])
            {
               long long y=(i*l+L2)*1LL;
               if((y%m)!=0&&(y%m+R2-L2)<m)
               {
                   f=1;
                   break;
               }
            }
        }
        if(f) cout<<"WIN"<<endl;
        else cout<<"LOSE"<<endl;
    }
}

链接:https://www.nowcoder.com/acm/contest/91/E
来源:牛客网

小Y吃苹果
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

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

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

输入描述:

输入数据只有一个整数N,表示小Y在N天前买了苹果。

输出描述:

输出一个整数,表示可能的数量种数。
示例1

输入

1

输出

2

说明

样例中小Y在一天前买了苹果,因此他只可能买了2个或者3个苹果,共2种情况。

这个就是直接找结论啊,试几个

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    cin>>n;
    cout<<(1<<n);
    return 0;
     
}

链接:https://www.nowcoder.com/acm/contest/91/F
来源:牛客网

1 + 2 = 3?
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

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

(表示按位异或运算)

输入描述:

第一行是一个正整数,表示查询次数。

接着有T行,每行有一个正整数,表示小Y的查询。

输出描述:

对于每一个查询N,输出第N个满足题中等式的正整数,并换行。
示例1

输入

4
1
2
3
10

输出

1
2
4
18

斐波那契 斐波那契 斐波那契重要的事情说三遍,找到结论然后模拟下

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
int main()
{
    ll fb[100];
    fb[1]=1;fb[2]=1;
    for(int i=3;i<=60;i++)
    {
        fb[i]=fb[i-1]+fb[i-2];
    }
    ll sum[100]={0};
    for(int i=1;i<=60;i++)
    {
        sum[i]=sum[i-1]+fb[i];
        //printf("i=%d sum[i]=%lld\n",i,sum[i]);
    }
    int t;
    ll n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&n);
        int x,t=1;
        ll kum=0;
        do
        {
            for(int i=1;i<=60;i++)
            {
                if(n>sum[i-1]&&n<=sum[i])
                {
                    x=i;break;
                }
            }
            kum+=1LL<<(x-1);
            n=n-sum[x-1]-1;
            //printf("x==%d\n",x);
            //printf("kum==%lld\n",kum);
        }while(n>1);
        //printf("%d\n",n);
        printf("%lld\n",kum+n);
    }
    return 0;
     
}

 

链接:https://www.nowcoder.com/acm/contest/91/I
来源:牛客网

二数
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

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

输入描述:

1 ≤ T ≤ 100, 1 ≤ n ≤ 10
100000
 − 1, T组数据的数字的十进制表示长度总和不超过1000000

输出描述:

每行一个整数 m 第 i 行表示第 i 个数所对应的“最邻近二数”
示例1

输入

5
42
11
1
2018
13751

输出

42
8
0
2020
8888

贪心找到左右两边的数,然后大数判断下,模拟不动啊

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
const ll N=1000000+5;
string add(string s1,string s2){
    string s;
    int len1,len2;
    len1=s1.size()-1; len2=s2.size()-1;
    int i=0,f=0;
    while(len1>-1&&len2>-1){
        int sum=f+(s1[len1--]-'0')+(s2[len2--]-'0');
        s+=sum%10+'0';
        f=sum/10;
    }
    while(len1>-1){
        int sum=f+(s1[len1--]-'0');
        s+=sum%10+'0';
        f=sum/10;
    }
    while(len2>-1){
        int sum=f+(s2[len2--]-'0');
        s+=sum%10+'0';
        f=sum/10;
    }
    if(f) s+='0'+f;
    reverse(s.begin(),s.end());
    return s;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        string s;
        int pos=-1;
        cin>>s;
        for(int i=0;s[i];i++)
        {
            int x=s[i]-'0';
            if(x%2)
            {
                pos=i;
                break;
            }
        }
        if(pos==-1)
            cout<<s;
        else
        {
            string r1,r2,r3,r4;
            int l=s.size();
            //-1 8888
            for(int i=0;i<pos;i++)r1+=s[i];
            r1+=s[pos]-1;
            for(int i=pos+1;i<l;i++)r1+="8";
            r3=add(s,s);
            //+1 0000
            if(s[pos]+1!=':')
            {
                for(int i=0;i<pos;i++)r2+=s[i];
                r2+=s[pos]+1;
                for(int i=pos+1;i<l;i++)r2+="0";
                r4=add(r1,r2);
                if(r3<=r4)
                {
                    if(r1.size()!=1&&r1[0]=='0')r1.erase(r1.begin());
                    cout<<r1;
                }
                else cout<<r2;
            }
            else
                cout<<r1;
        }
        cout<<endl;
    }
    return 0;
}

链接:https://www.nowcoder.com/acm/contest/91/L
来源:牛客网

K序列
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

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

输入描述:

第一行为两个整数 n, K, 以空格分隔,第二行为 n 个整数,表示 a[1] ∼ a[n],1 ≤ n ≤ 10
5
 , 1 ≤ a[i] ≤ 10
9
 , 1 ≤ nK ≤ 10
7

输出描述:

输出一个整数表示最长子序列的长度 m
示例1

输入

7 5
10 3 4 2 2 9 8

输出

6

是nk<1e7,所以还是取模。

我连续的是这样写的,按照题意是错的,但是数据水了

假如k特别大而且是连续的不失是一种好做法

#include <bits/stdc++.h>
using namespace std;
unordered_map<int,int>M;
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    int ma=0,s=0;
    M[0]=0;
    for(int i=1; i<=n; i++)
    {
        int p;
        scanf("%d",&p);
        s=(s+p)%k;
        if(M.count(s))ma=max(ma,i-M[s]);
        else M[s]=i;
    }
    printf("%d",ma);
    return 0;
}

正确的写法是这样的

#include<bits/stdc++.h>
using namespace std;
const int N=1e7+5;
int tmp[N],now[N];
int main()
{
    int n,k;
    scanf("%d %d",&n,&k);
    tmp[0]=1;
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        for(int i=0;i<k;i++)
        {
            if(tmp[i])
            {
                now[(i+x)%k]=max(now[(i+x)%k],tmp[i]+1);
            }
        }
        for(int i=0;i<k;i++)
            tmp[i]=max(tmp[i],now[i]);
    }
    cout<<tmp[0]-1;
    return 0;
}

 链接:https://www.nowcoder.com/acm/contest/91/B
来源:牛客网

合约数
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

在埃森哲,员工培训是最看重的内容,最近一年,我们投入了 9.41 亿美元用于员工培训和职业发展。截至 2018 财年末,我们会在全球范围内设立 100 所互联课堂,将互动科技与创新内容有机结合起来。按岗培训,按需定制,随时随地,本土化,区域化,虚拟化的培训会让你快速取得成长。小埃希望能通过培训学习更多ACM 相关的知识,他在培训中碰到了这样一个问题,

给定一棵n个节点的树,并且根节点的编号为p,第i个节点有属性值vali, 定义F(i): 在以i为根的子树中,属性值是vali的合约数的节点个数。y 是 x 的合约数是指 y 是合数且 y 是 x 的约数。小埃想知道对1000000007取模后的结果.

输入描述:

输入测试组数T,每组数据,输入n+1行整数,第一行为n和p,1<=n<=20000, 1<=p<=n, 接下来n-1行,每行两个整数u和v,表示u和v之间有一条边。第n+1行输入n个整数val1, val2,…, valn,其中1<=vali<=10000,1<=i<=n.

输出描述:

对于每组数据,输出一行,包含1个整数, 表示对1000000007取模后的结果

示例1

输入

2
5 4
5 3
2 5
4 2
1 3
10 4 3 10 5
3 3
1 3
2 1
1 10 1

输出

11
2

备注:

n>=10000的有20组测试数据

听说B题可做?但是我不会啊

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MD=1e9+7;
vector<int> v[20020],d[10005];
int n,rt,vis[10005];
ll val[20020],ans,f[20020];
void dfs(int x,int pre)
{
    for(auto X:d[val[x]])f[X]=(f[X]+x)%MD;
    ans=(ans+f[val[x]])%MD;
    for(auto X:v[x])if(X!=pre)dfs(X,x);
    for(auto X:d[val[x]])f[X]=(f[X]-x+MD)%MD;
}
int main()
{
    for(int i=2; i<=10000; i++)
        if(!vis[i])for(int j=i+i; j<=10000; j+=i)vis[j]=1;
    for(int i=4; i<=10000; i++)
        if(vis[i])for(int j=i; j<=10000; j+=i)d[j].push_back(i);
    int T;
    cin>>T;
    while(T--)
    {
        ans=0;
        cin>>n>>rt;
        memset(vis,0,sizeof vis);
        for(int i=1; i<=n; i++)v[i].clear();
        for(int i=1,x,y; i<n ; i++)
            cin>>x>>y,v[x].push_back(y),v[y].push_back(x);
        for(int i=1; i<=n; i++)cin>>val[i];
        dfs(rt,-1);
        cout<<ans<<'\n';
    }
}
posted @ 2018-04-18 14:03  暴力都不会的蒟蒻  阅读(413)  评论(0编辑  收藏  举报