传送门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求最大相同子序列