A Wasserstein Distance
題目描述
的體力。小埃的最終目的是通過在第一堆中挪動泥土,使得第一堆泥土最終的形態和第二堆相同,也就是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土堆的形態所需要花費的最小體力
輸入
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\n",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\n",ans); 30 tmp -= a[j]; 31 a[j] = 0; 32 } else{ 33 ans += (j-i)*tmp; 34 //printf("3:%d\n",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
輸入
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\n"; 10 else cout << "WIN\n"; 11 } 12 return 0; 13 }
E 小Y吃蘋果
題目描述
小Y買了很多蘋果,但他很貪吃,過了幾天一下就吃剩一只了。每一天小Y會數出自己的蘋果個數X,如果X是偶數,他就會吃掉
只蘋果;如果X是奇數,他就會吃掉
只蘋果。
你知道現在蘋果只剩下一只,並且小Y是在N天前買的蘋果,現在小Y想知道在那天買了多少蘋果。當然,可能性不止一種,你只需要求出他買的蘋果數量有多少種可能。
輸入描述:
輸入數據只有一個整數N,表示小Y在N天前買了蘋果。
輸出描述:
輸出一個整數,表示可能的數量種數。
輸入
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個滿足題中等式的正整數,並換行。
輸入
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 二數
題目描述
換句話說,給定一個十進制下最多10 5位的數字,請你求出和這個數字的差的絕對值最小的二數,若答案不唯一,輸出最小的那個。
輸入描述:
1 ≤ T ≤ 100, 1 ≤ n ≤ 10100000 − 1, T組數據的數字的十進制表示長度總和不超過1000000
輸出描述:
每行一個整數 m 第 i 行表示第 i 個數所對應的“最鄰近二數”
輸入
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\n"; 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序列
題目描述
輸入描述:
第一行為兩個整數 n, K, 以空格分隔,第二行為 n 個整數,表示 a[1] ∼ a[n],1 ≤ n ≤ 105 , 1 ≤ a[i] ≤ 109 , 1 ≤ nK ≤ 107
輸出描述:
輸出一個整數表示最長子序列的長度 m
輸入
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\n",i,j,a[j],a[i-1]); 20 MAX = j-i+1; 21 } 22 } 23 } 24 cout << MAX << endl; 25 return 0; 26 }
