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

Wasserstein Distance

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

题目描述

最近对抗生成网络(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<iostream>
using namespace std;
#include<cmath>
#include<cstring>
#include<cstdio>
typedef long long ll;
const ll maxn = 1e5+10;
ll a[maxn];
ll b[maxn];
int main(){
    ll n;
    ll t;
    scanf("%lld",&t);
    while(t--){
    scanf("%lld",&n);
    long long ans = 0;
    for(ll i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(ll i=1;i<=n;i++)
        scanf("%lld",&b[i]);
    for(ll i=1;i<=n;i++){
        ll c = b[i]-a[i];
        a[i+1] -= c;
        ans+=abs(c);
    }
    printf("%lld\n",ans);
    }
    return 0;
}

1 + 2 = 3?

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

题目描述

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

(表示按位异或运算)

输入描述:

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

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

输出描述:

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

输入

4
1
2
3
10

输出

1
2
4
18
做法:
找规律or数位DP
易知x的二进制数肯定满足不存在两个1相邻的情况。
所以,我们用数位DP可以快速得到小于等于p的符合条件数的个数
那么我们要找第n大,那么二分即可。需要注意的是,要找到的是
大于等于n的最左边的值,注意二分的写法
 1 #include<iostream>
 2 using namespace std;
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 typedef long long ll;
 7 ll a,b;
 8 ll f[100][3];
 9 int number[100];
10 int trans(ll p){
11     memset(number,0,sizeof(number));
12     if(p==0){
13       number[0]=0;
14       return 1;
15     }
16     int ws = 0;
17     while(p>0){
18         number[ws++] = p%2;
19         p/=2;
20     }
21     return ws;
22 }
23 ll dfs(int bit,int pre,int limit){
24   // cout<<bit<<" "<<pre<<" "<<limit<<"*\n";
25     if(bit==-1){
26         return 1;}
27     if(limit==0&&f[bit][pre]!=-1LL)
28         return f[bit][pre];
29     int up = limit?number[bit]:1;
30     ll ans = 0;
31   //  cout<<"UP:"<<up<<endl;
32     for(int i=0;i<=up;i++){
33          if(pre==1&&i==1)
34              continue;
35          ans = ans + dfs(bit-1,i,limit&&i==number[bit]);
36     } 
37     if(!limit)
38         f[bit][pre] = ans;
39     return ans;
40 }
41 ll get(ll n){
42     ll l = 1,r = 1e18;
43     while(l<=r){
44         ll mid = (l+r)/2;
45         int ws = trans(mid);
46         ll p = dfs(ws-1,0,1)-1;
47     //    cout<<mid<<" "<<p<<endl;
48         if(p<n)
49             l = mid+1;
50         else
51             r = mid-1;
52     }
53     return r+1;
54 }
55 int main(){
56     ll p;
57     memset(f,-1,sizeof(f));
58     int t;
59     cin>>t;
60     while(t--){
61     cin>>p;
62     ll ans = get(p);
63     cout<<ans<<endl;
64     }
65     return 0;
66 }

小Y吃苹果

题目略

输出2的n次方即可

 1 #include<iostream>
 2 using namespace std;
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 typedef long long ll;
 7 const ll maxn = 1e5+10;
 8 ll a[maxn];
 9 ll b[maxn];
10 int main(){
11     ll n;
12     ll p = 1;
13     cin>>n;
14     cout<<(p<<n);
15     return 0;
16 }

K序列

n^2暴力水过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define read(x) scanf("%lld",&x)
 4 #define out(x) printf("%lld",&x)
 5 #define cfread(x) scanf("%I64d",&x)
 6 #define cfout(x) printf("%I64d",&x)
 7 #define mian main
 8 #define min(x,y) (x<y?x:y)
 9 #define max(x,y) (x<y?y:x)
10 #define f(i,p,q,t) for(i=p;i<q;i+=t)
11 #define MAXN 110000
12 #define inf 0x3f3f3f3f
13 #define mem(x,t) memset(x,t,sizeof(x));
14 #define T true
15 #define F false
16 #define def -1*inf
17 typedef long long ll;
18 typedef long long LL;
19 typedef double dd;
20 int a[110000];
21 ll ssum[1100000];
22 ll sum = 0;
23 int main(){
24     ll n,p;
25     scanf("%lld%lld",&n,&p);
26     sum = 0;
27     ssum[0] = 0;
28     long long ans = 0;
29     for(int i=1;i<=n;i++){
30         scanf("%lld",&a[i]);
31         a[i]%=p;
32         if(a[i]==0)
33             a[i] = p;
34         sum +=a[i];
35         ssum[i] = sum;
36     }
37     for(int i=n;i>=1;i--){
38         int pp = 0;
39         for(int j=1;j<=i;j++){
40             if((ssum[i]-ssum[j-1])%p==0){
41                 ans = max(ans,i-j+1);
42                 pp =1;
43             //    cout<<j<<"->"<<i<<endl;
44                 break;
45             }
46         }
47     }
48     printf("%lld",ans);
49     return 0;
50 }
二数
链接:https://www.nowcoder.com/acm/contest/91/I
来源:牛客网

题目描述

我们把十进制下每一位都是偶数的数字叫做“二数”。
小埃表示自己很聪明,最近他不仅能够从小数到大: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
做法:(大数+贪心构造)
对于n,我们需要构造一个大于等于n的符合条件数字和小于等于n的符合条件的数字

构造大于等于n的符合条件的数方法:
从高位向地位扫
使最高位的非偶数位+1,并且处理好进位的情况。如果进位,亦需更新使前面高位的数依旧是偶数
更新完最高位非偶数位之后,后面的数,全部使之为0


构造小于等于n的符合条件的数方法:
从高位向地位扫
使最高位的非偶数位-1
更新完最高位非偶数位之后,后面的数,全部使之为8

然后大数减法,算出来两个数与原来数的差值,取差最小的答案输出即可。

  1 #include<iostream>
  2 using namespace std;
  3 #include<cstdio>
  4 #include<cstdlib>
  5 #include <stdio.h>
  6 #include <string.h>
  7 #include <ctype.h>
  8 #include<algorithm> 
  9 using namespace std; 
 10 
 11 #define MAXN 9
 12 #define MAXSIZE 10
 13 #define DLEN 1
 14 
 15 class BigNum
 16 { 
 17 private: 
 18     int a[110000];    //可以控制大数的位数 
 19     int len;       //大数长度
 20 public: 
 21     BigNum(){ len = 1;memset(a,0,sizeof(a)); }   //构造函数
 22     BigNum(const int);       //将一个int类型的变量转化为大数
 23     BigNum(const char*,int);     //将一个字符串类型的变量转化为大数
 24     BigNum(const BigNum &);  //拷贝构造函数
 25     BigNum &operator=(const BigNum &);   //重载赋值运算符,大数之间进行赋值运算
 26     
 27     friend istream& operator>>(istream&,  BigNum&);   //重载输入运算符
 28     friend ostream& operator<<(ostream&,  BigNum&);   //重载输出运算符
 29     
 30     BigNum operator+(const BigNum &) const;   //重载加法运算符,两个大数之间的相加运算 
 31     BigNum operator-(const BigNum &) const;   //重载减法运算符,两个大数之间的相减运算 
 32     BigNum operator*(const BigNum &) const;   //重载乘法运算符,两个大数之间的相乘运算 
 33     BigNum operator/(const int   &) const;    //重载除法运算符,大数对一个整数进行相除运算
 34     
 35     BigNum operator^(const int  &) const;    //大数的n次方运算
 36     int    operator%(const int  &) const;    //大数对一个int类型的变量进行取模运算    
 37     bool   operator>(const BigNum & T)const;   //大数和另一个大数的大小比较
 38     bool   operator>(const int & t)const;      //大数和一个int类型的变量的大小比较
 39     
 40     void print();       //输出大数
 41 }; 
 42 BigNum::BigNum(const int b)     //将一个int类型的变量转化为大数
 43 { 
 44     int c,d = b;
 45     len = 0;
 46     memset(a,0,sizeof(a));
 47     while(d > MAXN)
 48     {
 49         c = d - (d / (MAXN + 1)) * (MAXN + 1); 
 50         d = d / (MAXN + 1);
 51         a[len++] = c;
 52     }
 53     a[len++] = d;
 54 }
 55 BigNum::BigNum(const char*s,int l)     //将一个字符串类型的变量转化为大数
 56 {
 57     int t,k,index,i;
 58     memset(a,0,sizeof(a));
 59     len=l/DLEN;
 60     if(l%DLEN)
 61         len++;
 62     index=0;
 63     for(i=len-1;i>=0;i-=DLEN)
 64     {
 65         t=0;
 66         k=i-DLEN+1;
 67         if(k<0)
 68             k=0;
 69         for(int j=k;j<=i;j++)
 70             t=t*10+s[j]-'0';
 71         a[index++]=t;
 72     }
 73 }
 74 BigNum::BigNum(const BigNum & T) : len(T.len)  //拷贝构造函数
 75 { 
 76     int i; 
 77     memset(a,0,sizeof(a)); 
 78     for(i = 0 ; i < len ; i++)
 79         a[i] = T.a[i]; 
 80 } 
 81 BigNum & BigNum::operator=(const BigNum & n)   //重载赋值运算符,大数之间进行赋值运算
 82 {
 83     int i;
 84     len = n.len;
 85     memset(a,0,sizeof(a)); 
 86     for(i = 0 ; i < len ; i++) 
 87         a[i] = n.a[i]; 
 88     return *this; 
 89 }
 90 istream& operator>>(istream & in,  BigNum & b)   //重载输入运算符
 91 {
 92     char ch[MAXSIZE*4];
 93     int i = -1;
 94     in>>ch;
 95     int l=strlen(ch);
 96     int count=0,sum=0;
 97     for(i=l-1;i>=0;)
 98     {
 99         sum = 0;
100         int t=1;
101         for(int j=0;j<4&&i>=0;j++,i--,t*=10)
102         {
103             sum+=(ch[i]-'0')*t;
104         }
105         b.a[count]=sum;
106         count++;
107     }
108     b.len =count++;
109     return in;
110     
111 }
112 ostream& operator<<(ostream& out,  BigNum& b)   //重载输出运算符
113 {
114     int i;  
115     cout << b.a[b.len - 1]; 
116     for(i = b.len - 2 ; i >= 0 ; i--)
117     { 
118         cout.width(DLEN); 
119         cout.fill('0'); 
120         cout << b.a[i]; 
121     } 
122     return out;
123 }
124 
125 BigNum BigNum::operator+(const BigNum & T) const   //两个大数之间的相加运算
126 {
127     BigNum t(*this);
128     int i,big;      //位数   
129     big = T.len > len ? T.len : len; 
130     for(i = 0 ; i < big ; i++) 
131     { 
132         t.a[i] +=T.a[i]; 
133         if(t.a[i] > MAXN) 
134         { 
135             t.a[i + 1]++; 
136             t.a[i] -=MAXN+1; 
137         } 
138     } 
139     if(t.a[big] != 0)
140         t.len = big + 1; 
141     else
142         t.len = big;   
143     return t;
144 }
145 BigNum BigNum::operator-(const BigNum & T) const   //两个大数之间的相减运算 
146 {  
147     int i,j,big;
148     bool flag;
149     BigNum t1,t2;
150     if(*this>T)
151     {
152         t1=*this;
153         t2=T;
154         flag=0;
155     }
156     else
157     {
158         t1=T;
159         t2=*this;
160         flag=1;
161     }
162     big=t1.len;
163     for(i = 0 ; i < big ; i++)
164     {
165         if(t1.a[i] < t2.a[i])
166         { 
167             j = i + 1; 
168             while(t1.a[j] == 0)
169                 j++; 
170             t1.a[j--]--; 
171             while(j > i)
172                 t1.a[j--] += MAXN;
173             t1.a[i] += MAXN + 1 - t2.a[i]; 
174         } 
175         else
176             t1.a[i] -= t2.a[i];
177     }
178     t1.len = big;
179     while(t1.a[t1.len - 1] == 0 && t1.len > 1)
180     {
181         t1.len--; 
182         big--;
183     }
184     if(flag)
185         t1.a[big-1]=0-t1.a[big-1];
186     return t1; 
187 } 
188 
189 BigNum BigNum::operator*(const BigNum & T) const   //两个大数之间的相乘运算 
190 { 
191     BigNum ret; 
192     int i,j,up; 
193     int temp,temp1;   
194     for(i = 0 ; i < len ; i++)
195     { 
196         up = 0; 
197         for(j = 0 ; j < T.len ; j++)
198         { 
199             temp = a[i] * T.a[j] + ret.a[i + j] + up; 
200             if(temp > MAXN)
201             { 
202                 temp1 = temp - temp / (MAXN + 1) * (MAXN + 1); 
203                 up = temp / (MAXN + 1); 
204                 ret.a[i + j] = temp1; 
205             } 
206             else
207             { 
208                 up = 0; 
209                 ret.a[i + j] = temp; 
210             } 
211         } 
212         if(up != 0) 
213             ret.a[i + j] = up; 
214     } 
215     ret.len = i + j; 
216     while(ret.a[ret.len - 1] == 0 && ret.len > 1)
217         ret.len--; 
218     return ret; 
219 } 
220 BigNum BigNum::operator/(const int & b) const   //大数对一个整数进行相除运算
221 { 
222     BigNum ret; 
223     int i,down = 0;   
224     for(i = len - 1 ; i >= 0 ; i--)
225     { 
226         ret.a[i] = (a[i] + down * (MAXN + 1)) / b; 
227         down = a[i] + down * (MAXN + 1) - ret.a[i] * b; 
228     } 
229     ret.len = len; 
230     while(ret.a[ret.len - 1] == 0 && ret.len > 1)
231         ret.len--; 
232     return ret; 
233 }
234 int BigNum::operator %(const int & b) const    //大数对一个int类型的变量进行取模运算    
235 {
236     int i,d=0;
237     for (i = len-1; i>=0; i--)
238     {
239         d = ((d * (MAXN+1))% b + a[i])% b;  
240     }
241     return d;
242 }
243 BigNum BigNum::operator^(const int & n) const    //大数的n次方运算
244 {
245     BigNum t,ret(1);
246     int i;
247     if(n<0)
248         exit(-1);
249     if(n==0)
250         return 1;
251     if(n==1)
252         return *this;
253     int m=n;
254     while(m>1)
255     {
256         t=*this;
257         for( i=1;i<<1<=m;i<<=1)
258         {
259             t=t*t;
260         }
261         m-=i;
262         ret=ret*t;
263         if(m==1)
264             ret=ret*(*this);
265     }
266     return ret;
267 }
268 bool BigNum::operator>(const BigNum & T) const   //大数和另一个大数的大小比较
269 { 
270     int ln; 
271     if(len > T.len)
272         return true; 
273     else if(len == T.len)
274     { 
275         ln = len - 1; 
276         while(a[ln] == T.a[ln] && ln >= 0)
277             ln--; 
278         if(ln >= 0 && a[ln] > T.a[ln])
279             return true; 
280         else
281             return false; 
282     } 
283     else
284         return false; 
285 }
286 bool BigNum::operator >(const int & t) const    //大数和一个int类型的变量的大小比较
287 {
288     BigNum b(t);
289     return *this>b;
290 }
291 
292 void BigNum::print()    //输出大数
293 { 
294     int i;   
295     cout << a[len - 1]; 
296     for(i = len - 2 ; i >= 0 ; i--)
297     { 
298         cout.width(DLEN); 
299         cout.fill('0'); 
300         cout << a[i]; 
301     } 
302     cout << endl;
303 }
304 
305 BigNum c1,c2;
306 BigNum *l,*r,*m;
307 struct Number{
308     char s[110000];
309     int len;
310     void creat(char ss[],int n){
311         len  = n;
312         for(int i=1;i<=n;i++)
313             s[i] = ss[i-1] - '0';
314     }
315     char bs[110000];
316     int bslen;
317     char ms[110000];
318     int mslen;
319     void cbs(){;
320         int pre = 0;
321         memset(bs,0,sizeof(bs));
322         bslen = len;
323         for(int i=1;i<=len;i++){
324             bs[i] = s[i];
325             if(pre==1){
326                 bs[i] = 0;
327                 continue;
328             }
329             if(bs[i]%2==0)
330                 continue;
331             bs[i] = bs[i]+1;
332             pre = 1;
333             int j = i;
334             while(bs[j]>=10&&j>=0){
335                 bs[j-1] += bs[j]/10;
336                 bs[j]%=10;
337                 if(bs[j-1]%2!=0)
338                     bs[j-1]+=1;
339                 j-=1;
340             }
341         }
342         if(bs[0]>0){
343             bslen+=1;
344             for(int i=bslen;i>=1;i--)
345                 bs[i] = bs[i-1];
346         }
347         bs[0] = 0;
348         int qd = 0;
349         int ppre = 0;
350         for(int i=0;i<=len;i++){
351             if(bs[i]==0)
352                 qd+=1;
353             else{
354                 ppre = 1;
355                 break;
356             }
357         }
358         if(ppre==0){
359             bs[1]=0;
360             bslen=1;
361             return;
362         }
363         if(qd>1)
364         for(int i=1;i<=len;i++){
365             bs[i] = bs[i+qd-1];
366         }
367         bslen -= (qd-1);
368     }
369     void mbs(){
370         int pre = 0;
371         memset(ms,0,sizeof(ms));
372         mslen = len;
373         for(int i=1;i<=len;i++){
374             ms[i] = s[i];
375             if(pre==0){
376                 if(ms[i]%2==0)
377                     continue;
378                 ms[i] -= 1;
379                 pre = 1;    
380             }
381             else{
382                 ms[i] = 8;
383             }
384         }
385         int qd = 0;
386         int ppre = 0;
387         for(int i=0;i<=len;i++){
388             if(ms[i]==0)
389                 qd+=1;
390             else{
391                 ppre = 1;
392                 break;
393             }
394         }
395         if(ppre==0){
396             ms[1] = 0;
397             mslen = 1;
398             return;
399         }
400         if(qd>1)
401         for(int i=1;i<=len;i++){
402             ms[i] = ms[i+qd-1];
403         }
404         mslen -= (qd-1);
405     }
406     bool check(){
407             for(int i=1;i<=bslen;i++)
408                 bs[i]+='0';
409             for(int i=1;i<=mslen;i++)
410                 ms[i]+='0';
411             for(int i=1;i<=len;i++)
412                 s[i]+='0';
413         l=new BigNum(bs+1,bslen),r=new BigNum(ms+1,mslen),m=new BigNum(s+1,len);
414     //    cout<<(*l)<<" "<<(*m)<<" "<<(*r)<<endl;
415         c1 = (*l)-(*m);
416         c2 = (*m)-(*r);
417     //    cout<<c1<<" "<<c2<<endl;
418         if(c2>c1)
419             for(int i=1;i<=bslen;i++)
420                 printf("%c",bs[i]);
421         else
422             for(int i=1;i<=mslen;i++)
423                 printf("%c",ms[i]);
424         putchar('\n');        
425         delete l;
426         delete r;
427         delete m; 
428         return 0;
429     }
430 };
431 char s[300000];
432 Number a;
433 void deal(){
434     scanf("%s",s);
435     a.creat(s,strlen(s));
436     a.cbs();
437     a.mbs();
438     a.check();    
439 }
440 int main(){
441     int t;
442     scanf("%d",&t);
443     while(t--){
444         deal();
445     }
446     return 0;
447 }
写于 2018/4/15 17:02

posted @ 2018-04-15 17:03  晓风微微  阅读(354)  评论(0编辑  收藏  举报