傳送門c++
唐和江進行遊戲,規則是,對於給定的n和k,唐先手,在黑板上寫出[1,k]的數,再加下來每次寫的數必須>=上次的數加1,<=上次的數加k,誰寫出的先超過n即輸數組
巴什博弈的變形。巴什博弈是n到0輸,如今是1到n輸,咱們能夠把它當作n - 1到0的巴什博弈便可,當(n - 1)% k == 0時先手輸,即江贏,不然唐贏函數
#include<bits/stdc++.h> using namespace std; typedef long long ll; int main() { int n, m; while(cin>>n>>m) { if(n == 0 && m == 0) break; else { if((n - 1) % (m + 1) == 0) cout<<"Jiang\n"; else cout<<"Tang\n"; } } return 0; }
給你n個數和x,問你這個n個數能夠進行無數次兩兩相加,問你通過操做後數組的數對k向上取整的最小值和最大值爲多少spa
對於任意一個數k,咱們能夠把它拆成兩部分看:(k / x ) * x + k % 4,也就是x的倍數加上對x的餘數,因爲是向上取整,因此餘數不管是多少都無所謂(0除外),都會進1的,因此最小值只須要咱們讓每一個數的餘數儘可能爲0便可,因此能夠把全部的值加起來,對x向上取整便可。.net
而對於最大值,就是每一個數對x向上取整,而後加起來便可。code
由於我忘了向上取整的函數是多少,因此我就用(k + x - 1)/ x 來代替函數,其結果是同樣的blog
#include<bits/stdc++.h> using namespace std; typedef long long ll; inline int IntRead() { char ch = getchar(); int s = 0, w = 1; while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { s = s * 10 + ch - '0', ch = getchar(); } return s * w; } int main() { ll t, n, x; ll tr[100005]; t = IntRead(); while(t--) { memset(tr, 0, sizeof(tr)); ll ans = 0, sum = 0, k = 0; n = IntRead(); x = IntRead(); for(int i = 1; i <= n; i++) { tr[i] = IntRead(); sum += tr[i];//求和 ans += (tr[i] + x - 1) / x;//對每一個數進行向上取整 } ll minx = (sum + x - 1) / x;//對和進行向上取整 ll maxn = ans; cout<<minx<<' '<<maxn<<'\n'; } return 0; }
給出n+m個數,n個數與m個數是兩列數,但他們原本是一列數,問你這列數如何擺放能放下面的f(a)的值最大(這兩列數內的數相對順序不變)排序
想一下就能夠知道這個題考察的是前綴和,只需對兩堆數求前綴和便可,但記得求完前綴和與0比大小(我就這樣不當心wa了一發,逃索引
#include<bits/stdc++.h> using namespace std; typedef long long ll; inline int IntRead() { char ch = getchar(); int s = 0, w = 1; while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { s = s * 10 + ch - '0', ch = getchar(); } return s * w; } int main() { ll t, n, m, ar[105],br[105],arr[105], brr[105]; t = IntRead(); while(t--) { ll max1 = -1e9, max2 = -1e9; memset(arr, 0, sizeof(arr));//初始化 memset(brr, 0, sizeof(brr)); memset(ar, 0, sizeof(ar)); memset(br, 0, sizeof(br)); n = IntRead(); for(int i = 1; i <= n; i++) { ar[i] = IntRead(); } for(int i = 1; i <= n; i++) { arr[i] = arr[i - 1] + ar[i]; max1 = max(max1, arr[i]);//找最大前綴和 } m = IntRead(); for(int i = 1; i <= m; i++) { br[i] = IntRead(); } for(int i = 1; i <= m; i++) { brr[i] = brr[i - 1] + br[i]; max2 = max(max2, brr[i]);//一樣是找最大前綴和 } max1 = max(0, max1); max2 = max(0, max2); if(max1 <= 0 && max2 >= 0) cout<<max2<<'\n'; else if(max1 <= 0 && max2 <= 0) cout<<0<<'\n'; else if(max1 >= 0 && max2 >= 0) cout<<max1 + max2<<'\n'; else if(max1 >= 0 && max2 <= 0) cout<<max1<<'\n'; if(max1 <= 0 && max2 >= 0) cout<<max2<<'\n'; else if(max1 <= 0 && max2 <= 0) cout<<0<<'\n'; else if(max1 >= 0 && max2 >= 0) cout<<max1 + max2<<'\n'; else if(max1 >= 0 && max2 <= 0) cout<<max1<<'\n'; cout<<max1 + max2<<'\n'; } return 0; }
給你一個n個數,和一個數x,從第一個數開始進行判斷,若是能除得盡就將整除後獲得的數按整除的份數放到這堆數的後面,一直這樣下去,最終求得這堆數的和遊戲
舉個栗子:
1 2 ##1是這個堆數原本的數量,2是除數
12 ##12 是那對數
12 6 6 3 3 3 3 ##12除2得道兩個6,因此放在那對數裏面,6除以2獲得兩個3,6除以2獲得兩個3,3除不盡2,因此中止下來
我當時想用數組來作,可是怕爆了,因此想換queue,發現不能用迭代器,還怕TLE,就另闢蹊徑:由於每次都是把除完的數全放到後面,因此一個數除完放在後面,他們的和是不變的,即12 -> 12 6 6 3 3 3 3, 6+6 = 12, 3 + 3 = 6 。至關於12 * 3。因此就沒必要循環跑,只要知道算了幾回和便可,也就是要肯定是哪裏先出現奇數,只須要單獨寫個函數,對每一個數求須要除幾回2能變成奇數便可,靠前的最小數便是咱們要找的
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll tr[100005], ar[100005]; ll t, n, x, k, sum = 0; ll f(ll y)//這是函數f(),用來求除幾回2能獲得奇數的 { ll len = 0; while(1) { if(y % x == 0) { y /= x; len++; } else break; } return len; } int main() { cin>>t; while(t--) { memset(tr, 0, sizeof(tr));//由於是多組輸入,因此千萬不要忘記清0數組 memset(ar, 0, sizeof(ar)); sum = 0; ll step = 1, minx = 1e9; cin>>n>>x; for(int i = 1; i <= n; i++) { cin>>tr[i]; sum += tr[i];//記錄一次的總和 ar[i] = f(tr[i]); if(ar[i] < minx)//比較,找到位置 { step = i;//記錄位置 minx = ar[i];//更新最小值 } } ll ans = (f(tr[step]) + 1) * sum;//+1是由於要算上剛開始的數的和 for(int i = 1; i <= step - 1; i++) { ans += tr[i];//由於上面求的step不必定是第一個數,因此確定會加上其餘的,你寫個例子就懂了,這裏不贅述 } cout<<ans<<endl; } return 0; }
給你一個字符串,讓你求其前綴串是不是循環串,若是是就輸出位置和循環次數
上次剛作了一個問字符串是否是循環子串的題,這個題就是她的變式,只不過此次須要循環求其前綴串,上次只須要求這個字符串,思路都是求i - next[i],看看字符串的長度可否除盡這個數便可
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll next1[1000005], len1; string s; void getnext1()//第一個字符串的next數組的構造 { int j, k; j = 0; k = -1; next1[0] = -1; while(j < len1) { if(k == -1 || s[j] == s[k]) next1[++j] = ++k; else k = next1[k]; } } int main() { int t, q = 1; while(cin>>len1 && len1) { cout<<"Test case #"<<q<<endl; q++; cin>>s; memset(next1, 0, sizeof(next1)); getnext1(); for(int i = 1; i < len1; i++)//由於題中說從第二個字符開始,因此至關於字符串的1的索引 {//由於輸出的是字符的位置,不是從0開始的,因此要稍加改變 int a = i + 1 - next1[i + 1]; if((i + 1) % a == 0 && (i + 1) / a != 1) cout<<i + 1<<' '<<(i + 1) / a<<endl; } cout<<endl; } return 0; }
求兩個字符串最大公共子序列
dp
當s[i] == ss[j],那麼對於s[i]和ss[j]的最大公共子序列就至關因而s[i - 1]與ss[j - 1]的最大公共子序列。
當s[i] != ss[j],那麼對於s[0 ……i] 和 ss[0 ……j]的最大公共子序列的值是s[0 …… i-1]與ss[0……j]的最大公共子序列的長度 或 s[0 …… i]與ss[0 …… j - 1]的最大公共子序列的長度,由於是最大,因此取最大值便可
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll dp[1005][1005]; string s, ss; int main() { while(cin>>s>>ss) { memset(dp, 0, sizeof(dp)); int n = s.size(); int m = ss.size(); for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { if(s[i - 1] == ss[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1; else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); } } cout<<dp[n][m]<<'\n'; } return 0; }
n個朋友,m個禮物,禮物是c[],朋友的序號是tr[]
對於每一個朋友,送的東西有兩種選擇,一是從第一個到第tr[i]個禮物裏面挑一個,二是直接送第c[i]塊錢,切記,每一個禮物只有一個,讓你花最少的錢解決全部人的東西。
貪心。由於禮物的價值的升序排列,全部能夠對朋友的序號排序,序號大的人選擇多,但直接塞錢貴,序號小的選擇少,但塞錢便宜啊,因此咱們能夠從序號大的開始循環,禮物從小的開始給,給完就換下一個,當禮物送完或者,剩下的禮物貴於直接塞錢,那就塞錢!
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll t, sum, k, n, m, tr[300005],c[300005]; inline int IntRead(){ char ch = getchar(); int s = 0, w = 1; while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0', ch = getchar();} return s * w; } int main() { t = IntRead(); while(t--) { n = IntRead(); m = IntRead(); for(int i = 1; i <= n; i++) tr[i] = IntRead(); for(int i = 1; i <= m; i++) c[i] = IntRead(); sort(tr + 1, tr + 1 + n); k = 1; sum = 0; for(int i = n; i > 0; i--) { if(tr[i] > k) sum += c[k++]; else sum += c[tr[i]]; } cout<<sum<<endl; } return 0; }
I題妥妥的巴什博弈,我前一天還剛看過這個題,結果當時沒仔細看題,草草了事,致使今日作題明明知道作法卻由於0%x=0都不知道,樣例死都算不對,就不敢寫,後來寫出來運行後發現0%x=0,人都傻了
B題一個簡單的思惟題,開始想複雜了,後來發現不必那樣算,只須要算一下全部的和以及對每一個數向上取整的和便可
H題一個前綴和題,求兩列數的前綴和的值的和的最大值便可,記得求完前綴和不要直接相加,要看看是否是小於0!
B題也是思惟題,算一下是哪一個數最靠前且除2出現次數最小,而後將最後的和分爲兩部分算便可
K題循環子串的問題
C題貪心
G題dp求最大相同子序列