Wasserstein Distance
链接:https://www.nowcoder.com/acm/contest/91/A
来源:牛客网
题目描述
最近对抗生成网络(GAN)很火,其中有一种变体WGAN,引入了一种新的距离来提高生成图片的质量。这个距离就是Wasserstein距离,又名铲土距离。
这个问题可以描述如下:
有两堆泥土,每一堆有n个位置,标号从1~n。第一堆泥土的第i个位置有a
i克泥土,第二堆泥土的第i个位置有b
i克泥土。小埃可以在第一堆泥土中任意移挪动泥土,具体地从第i个位置移动k克泥土到第j个位置,但是会消耗
的体力。小埃的最终目的是通过在第一堆中挪动泥土,使得第一堆泥土最终的形态和第二堆相同,也就是a
i=b
i (1<=i<=n), 但是要求所花费的体力最小
左图为第一堆泥土的初始形态,右图为第二堆泥土的初始形态,颜色代表了一种可行的移动方案,使得第一堆泥土的形态变成第二堆泥土的形态
输入描述:
输入测试组数T,每组测试数据,第一行输入n,1<=n<=100000,紧接着输入两行,每行n个整数,前一行为a1
, a2
,…,an
,后一行为b1
,b2
,…,bn
.其中0<=ai
,bi
<=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 }
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...,他想知道从一个数开始数最少的数就得到一个二数。但是聪明的小森已经偷偷在心里算好了小埃会数到哪个二数,请你求出他要数到哪个数吧。
换句话说,给定一个十进制下最多10 5位的数字,请你求出和这个数字的差的绝对值最小的二数,若答案不唯一,输出最小的那个。
换句话说,给定一个十进制下最多10 5位的数字,请你求出和这个数字的差的绝对值最小的二数,若答案不唯一,输出最小的那个。
也就是说,给定数字n,求出m,使得abs(n-m)最小且m[i] mod 2 = 0
输入描述:
1 ≤ T ≤ 100, 1 ≤ n ≤ 10100000
− 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