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


    A Wasserstein Distance

    题目描述

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


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

    从左到右扫描,遇见ai小于bi就从ai的后面最近的拿,大于的话就把多余的放在ai+1上。

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <cstring>
     4 #include <cmath>
     5 #define ll long long
     6 using namespace std;
     7 const int N = 100010;
     8 ll a[N], b[N];
     9 int main() {
    10     ll t, n;
    11     scanf("%lld",&t);
    12     while(t--) {
    13         scanf("%lld",&n);
    14         ll ans = 0;
    15         for(int i = 1; i <= n; i ++) scanf("%lld",&a[i]);
    16         for(int i = 1; i <= n; i ++) scanf("%lld",&b[i]);
    17         for(ll i = 1; i <= n; i ++) {
    18             if(a[i] == b[i])continue;
    19             if(a[i] > b[i]) {
    20                 a[i+1] += a[i] - b[i];
    21                 ans += a[i] - b[i];
    22             //  printf("1:%d
    ",ans);
    23             }
    24             if(a[i] < b[i]) {
    25                 ll tmp = b[i]-a[i];
    26                 for(ll j = i+1; j <= n; j ++) {
    27                     if(tmp >= a[j]) {
    28                         ans += abs(j-i)*a[j];
    29                         //printf("2:%d
    ",ans);
    30                         tmp -= a[j];
    31                         a[j] = 0;
    32                     } else{
    33                         ans += (j-i)*tmp;
    34                         //printf("3:%d
    ",ans);
    35                         a[j] -= tmp;
    36                         break;
    37                     }
    38                 }
    39             }
    40         }
    41         cout << ans << endl;
    42     }
    43     return 0;
    44 }

    B 合约数点击这里

    D 数字游戏

    题目描述

    小埃和小森在玩一个数字游戏,小埃先从区间[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

    这个看能不能%mod等于0关键看n2。
    如果[l2,r2]的区间小于mod的话,假设在[l1,r2]之中选择x,那么组合的数区间为[xl2,xr2] 中会有一个数使的这个区间%mod不等于0。
    如果[l2,r2]的区间大于mod的话,组合的区间为[xl2,xr2],一定会存在一个数%mod等于0。
     1 #include <iostream>
     2 using namespace std;
     3 
     4 int main() {
     5     int t, l1, l2, r1, r2, mod;
     6     cin >> t;
     7     while(t--) {
     8         cin >> l1 >> r1 >> l2 >> r2 >> mod;
     9         if(r2-l2 >= mod-1) cout << "LOSE
    ";
    10         else cout << "WIN
    ";
    11     }
    12     return 0;
    13 }

    E 小Y吃苹果

    题目描述

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

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

    输入描述:

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

    输出描述:

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

    输入

    1

    输出

    2

    说明

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

    签到题
     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <cstring>
     4 #include <vector>
     5 using namespace std;
     6 int main() {
     7     int n, ans = 0;
     8     cin >> n;
     9     cout << (1<<n) << endl;
    10     return 0;
    11 }

    F 1 + 2 = 3?

    题目描述

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

    (表示按位异或运算)

    输入描述:

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

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

    输出描述:

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

    输入

    4
    1
    2
    3
    10

    输出

    1
    2
    4
    18

    要想x^(2*x) == 3*x 其实就是要让x的二进制表示没有相邻的1,这样就好算了

    当只有一位时,就只有1
    两位时,至于10
    三位时,100、101
    四位时,1000、1001、1010
    用数组dp保持第i位时的数量,很容易发现dp[i] = dp[i-1] + dp[i-2];

    当要算第n个数时,要让dp数组前缀和。这样dp[i]表示,当位数最多为i位时最多有多少个。
    所以可得,dp[i]+1表示第i+1位的最新数位1<<i;
    这样求第n个数时,只需查看dp[i]+1 <= n < dp[i+1]+1即可,然后依次减去dp[i]+1。
     1 #include <iostream>
     2 #include <stdio.h>
     3 #define ll long long
     4 using namespace std;
     5 ll dp[61], n, sum[61];
     6 int main() {
     7     dp[1] = 1;
     8     dp[2] = 1;
     9     for(int i = 3; i <= 60; i ++) {
    10         dp[i] = dp[i-1]+dp[i-2];
    11     }
    12     for(int i = 1; i <= 60; i ++) {
    13         dp[i] = dp[i] + dp[i-1];
    14     }
    15     //cout << dp[60] << endl;
    16     int t;
    17     cin >> t;
    18     while(t--) {
    19         ll ans = 0;
    20         cin >> n;
    21         while(n) {
    22             for(int i = 0; i <= 60; i ++) {
    23                 if((dp[i+1]+1) > n && n >= (dp[i]+1)) {
    24                     ans += (1LL<<i);
    25                 //  cout << ans << endl;
    26                     n -= (dp[i]+1LL);
    27                     break;
    28                 }
    29             }
    30         }
    31         cout << ans << endl;
    32     }
    33     return 0;
    34 }

    I 二数

    题目描述

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

    有规律,先找到第一个奇数,让它加1,然后让后面的全部变成0,或者让它加1,让后面的全部变成8,看那个数相差最小,相同的话输出最小的数。
      1 #include <iostream>
      2 #include <cstring>
      3 #include <stdio.h>
      4 #define MAX 1000010
      5 using namespace std;
      6 const int N = 1e6+10;
      7 char str[N], str1[N], str2[N];
      8 int sum1[MAX] = {0};
      9 int sum2[MAX] = {0};
     10 
     11 int Subtraction(char num1[], char num2[], int sum[])
     12 {
     13     int i, j, len, blag;
     14     char *temp;
     15     int n2[MAX] = {0};
     16     int len1 = strlen(num1);
     17     int len2 = strlen(num2); 
     18     blag = 0; 
     19     if(len1 < len2) 
     20     {
     21         blag = 1; 
     22         temp = num1;
     23         num1 = num2;
     24         num2 = temp;
     25         len = len1;
     26         len1 = len2;
     27         len2 = len;
     28     }
     29     else if(len1 ==len2) 
     30     {  
     31         for(i = 0; i < len1; i++)
     32         {
     33             if(num1[i] == num2[i])
     34                 continue;
     35             if(num1[i] > num2[i])
     36             {
     37                 blag = 0; 
     38                 break;
     39             } 
     40             else
     41             {
     42                 blag = 1; 
     43                 temp = num1;
     44                 num1 = num2;
     45                 num2 = temp;
     46                 break;
     47             } 
     48         } 
     49     }
     50     len = len1>len2 ? len1 : len2; 
     51     for (i = len1-1, j = 0; i >= 0; i--, j++) 
     52         sum[j] = num1[i] - '0';
     53 
     54     for (i = len2-1, j = 0; i >= 0; i--, j++)
     55         n2[j] = num2[i] - '0';
     56    
     57     for (i = 0; i <= len; i++)
     58     {
     59         sum[i] = sum[i] - n2[i]; 
     60         if (sum[i] < 0)   
     61         {    
     62             sum[i] += 10;
     63             sum[i+1]--;
     64         }
     65     }
     66     
     67     for (i = len1-1; i>=0 && sum[i] == 0; i--)
     68         ;
     69     len = i+1;
     70     if(blag==1)
     71     {
     72         sum[len] = -1;  
     73         len++;
     74     }
     75     return len;   
     76 }
     77 
     78 
     79 
     80 void init() {
     81     int len = strlen(str+1);
     82     //cout << len << endl;
     83     int i = 1;
     84     //cout << "dsadsa
    ";
     85     while((str[i]-'0')%2==0 && i <= len) {
     86         str1[i] = str[i];
     87         str2[i] = str[i];
     88         i++;
     89     }
     90     
     91     if(str[i]=='9' && i <= len){
     92         str1[i-1] += 2;
     93         str1[i] = '0';
     94         str2[i] = str[i] - 1;
     95     } else if(i <= len){
     96         str1[i] = str[i] + 1;
     97         str2[i] = str[i] - 1;
     98     }
     99     
    100     for(int j = i+1; j <= len; j ++) {
    101         str1[j] = '0';
    102         str2[j] = '8';
    103     }
    104     i = 1;
    105     int j = 1;
    106     int len1,len2;
    107     while(str2[i]=='0' && i < len)i++;
    108    // cout << str1+1 << endl;
    109    // cout << str2+i << endl;
    110     if(str1[0] == '2') {
    111         j = 0;
    112     }
    113     len1 = Subtraction(str1+j, str+1, sum1);
    114     len2 = Subtraction(str+1, str2+i, sum2); 
    115     //cout << sum1[0] << ' ' << sum2[0] << endl;
    116    // cout << len1 << ' ' << len2 << endl;
    117     if(len1 < len2) {
    118         cout << str1+j << endl;
    119     }else if(len1 > len2) {
    120         cout << str2+i << endl;
    121     } else {
    122         bool flag = true;
    123         for(int k = len1-1; k >= 0; k --) {
    124             if(sum1[k] < sum2[k]) {
    125                 flag = false;
    126                 break;
    127             } else if(sum1[k] > sum2[k]){
    128                 break;
    129             }
    130         }
    131         if(flag) cout << str2+i << endl;
    132         else cout << str1+j << endl;
    133     }
    134 }
    135 
    136 int main() {
    137     int t;
    138     cin >> t;
    139     while(t--) {
    140         memset(str,0,sizeof(str));
    141         memset(str1,0,sizeof(str1));
    142         memset(str2,0,sizeof(str2));
    143         memset(sum1,0,sizeof(sum1));
    144         memset(sum2,0,sizeof(sum2));
    145         cin >> str+1;
    146         init();
    147     }
    148     return 0;
    149 }

     L K序列

    题目描述

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

    输入描述:

    第一行为两个整数 n, K, 以空格分隔,第二行为 n 个整数,表示 a[1] ∼ a[n],1 ≤ n ≤ 105 , 1 ≤ a[i] ≤ 109 , 1 ≤ nK ≤ 107

    输出描述:

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

    输入

    7 5
    10 3 4 2 2 9 8

    输出

    6

    暴力即可解决。
    动态规格解点击
     1 #include <iostream>
     2 #include <stdio.h>
     3 #define ll long long
     4 using namespace std;
     5 const int N = 1e5+10;
     6 ll a[N];
     7 int main() {
     8     int n, k;
     9     scanf("%d %d",&n, &k);
    10     for(int i = 1; i <= n; i ++) {
    11         scanf("%d",&a[i]);
    12         a[i] += a[i-1];
    13     }
    14     int MAX = 0;
    15     for(int i = 1; i <= n; i ++) {
    16         for(int j = n; j >= 1; j --) {
    17             if(MAX >= j-i+1) break;
    18             if((a[j]-a[i-1])%k==0 && j-i+1 > MAX) {
    19                 //printf("%d %d %d %d
    ",i,j,a[j],a[i-1]);
    20                 MAX = j-i+1;
    21             }
    22         }
    23     }
    24     cout << MAX << endl;
    25     return 0;
    26 }
  • 相关阅读:
    关于回调函数的初探
    细节决定成败
    数据的导航与跳转
    如何在同一页面显示父子表的内容
    从Request到Response之间的所有事件发生的顺序
    如何更改网站的一些公共数据
    如何实现计数器
    DataTable.Select方法
    登出代码
    如何构建自定义控件
  • 原文地址:https://www.cnblogs.com/xingkongyihao/p/8848499.html
Copyright © 2020-2023  润新知