寒假训练总结
1. HDU - 2037
思路:很经典的一道贪心 ,越早结束就能看越多的节目。
细节:用结构体保存每组数据,自定义sort排序,根据结束时间大小排序,要注意,如果结束时间相同,就根据开始时间排序,开始越晚,之前能看的节目就越多。
bool cmp(pro a, pro b) { if (a.b != b.b) return a.b < b.b; else return a.a > b.a; }
知识点:贪心思想,结构体,sort
总结:贪心就是找局部的最优解,有时候跟dp容易搞混,此时有些题目事件是加权的,不宜用贪心
2. HDU - 1176
思路:dp
细节:先确定状态,用dp[i][j]表示在第i秒,坐标为j时的馅饼数,因为此时的状态可以由上一秒的三种状态转移来,所以状态转移方程为dp[i][j] = Max(dp[i - 1][j-1], dp[i - 1][j], dp[i - 1][j + 1]) + a[i][j],其中a[i][j]表示第i秒j点上的馅饼数。
1 dp[1][4] = a[1][4]; 2 dp[1][5] = a[1][5]; 3 dp[1][6] = a[1][6]; 4 for(int i=2;i<=maxt;i++) 5 for (int j = 0; j <= 10; j++) 6 { 7 dp[i][j] = Max(dp[i - 1][j-1], dp[i - 1][j], dp[i - 1][j + 1]) + a[i][j]; 8 ans = max(dp[i][j], ans); 9 }
知识点:动态规划
总结:动态规划解题四步:①分解为子问题②确定状态③确定边界值④确定状态转移方程。
3. Codeforces Round #538 (Div. 2) B
思路:记录前k*m个最大值的位置
细节:用结构体保存值和索引,先根据值的大小排序,再对前m*k个数根据索引值排序
知识点:sort自定义排序
总结:纯思维题,题目说的是分成k段,每段前m大的数,也就等价于全序列的前k*m大的数
4. 牛客寒假算法基础训练营4 E
思路:2^n对10^9+7取模
细节:欧拉降幂套板子
1 ll quickPow(ll a,ll b) 2 { 3 ll ans = 1; 4 a %= mod; 5 while(b) 6 { 7 if(b&1) ans = (ans * a) % mod; 8 a = a * a % mod; 9 b >>= 1; 10 } 11 return ans; 12 } 13 ll euler(ll n) 14 { 15 ll res = n; 16 for(int i = 2; i*i < n; i++) 17 { 18 if(n % i == 0) 19 res = res / i * (i-1); 20 while(n%i==0) 21 n /= i; 22 } 23 if(n > 1) 24 res = res / n * (n-1); 25 return res; 26 }
知识点:欧拉降幂
总结:这是个板子。
5. 2018-2019 ACM-ICPC, Asia Jiaozuo Regional Contest I
思路:左右互取
细节:本题在求距离时利用前缀和思想可大大减少复杂度。
1 for (ll i = 2; i <= n; i++) 2 { 3 ll x; scanf("%I64d", &x); 4 a[i] = a[i - 1] + x; 5 }
知识点:前缀和,贪心
总结:对前缀和还不是很熟悉,以及在选取点的时候用到了贪心也没想到,要多在这方面做题
6. Codeforces Round #500 (Div. 2)B
思路:由于按位与操作不管几次结果都不变,结果只有-1,0,1,2。0表示原序列有至少两个数字相同,1表示一次按位与后与原序列有相同的数,2表示两个数按位与后有相同的数
细节:用两个数组分别保存原序列各个数字的个数以及按位与操作后结果的个数
1 #include<bits/stdc++.h> 2 const int M = int(1e5) + 5; 3 using namespace std; 4 int a[M], b[M], c[M]; 5 int main() 6 { 7 memset(b, 0, M * sizeof(int)); 8 memset(c, 0, M * sizeof(int)); 9 int n, x; 10 cin >> n >> x; 11 for (int i = 0; i < n; i++) 12 { 13 cin >> a[i]; 14 b[a[i]]++;//记录输入的个数 15 if ((a[i] & x) != a[i]) 16 c[a[i] & x]++;//记录结果的个数 17 } 18 19 for(int i=0;i<n;i++) 20 if (b[a[i]] >= 2) 21 { 22 cout << 0 << endl; 23 return 0; 24 } 25 26 for(int i=0;i<n;i++) 27 if (c[a[i]] > 0) 28 { 29 cout << 1 << endl; 30 return 0; 31 } 32 33 for (int i = 0; i < n; i++) 34 if (c[a[i]&x] >= 2) 35 { 36 cout << 2 << endl; 37 return 0; 38 } 39 40 cout << -1 << endl; 41 return 0; 42 }
知识点:按位与a&b不论操作多少次结果不变
总结:位运算由于直接对内存进行操作,所以非常快。按位与还可用于判断整数奇偶性。平常没怎么重视位运算,做了几题发现位运算特别好用。
7. Codeforces Round #539 (Div. 2) C
思路:上式等价为al^al+^......ar-1^ar=0,可利用前缀和的思想进行求解,用a数组保存a0连续异或到ai的值,上式即等价于al=ar。
细节:由于题目只要考虑r-l+1为偶数的情况,易得r,l同奇偶,用二维数组b记录
1 #include<bits/stdc++.h> 2 #define inf 0x3f3f3f3f 3 typedef long long ll; 4 const int M = int(1e5)*3 + 5; 5 using namespace std; 6 ll a[M],b[2][(1<<20)+3]; 7 int main() 8 { 9 int n; cin >> n; 10 ll ans = 0; 11 b[0][0] = 1; 12 for (int i = 1; i <= n; i++) 13 { 14 int x; 15 cin >> x; 16 a[i] = a[i - 1] ^ x; 17 ans += b[i % 2][a[i]]; 18 b[i % 2][a[i]]++; 19 } 20 cout << ans << endl; 21 return 0; 22 }
知识点:异或运算具有自反性,即a^b^b=a,且a^0=a
总结:位运算真的很重要!!!
8.Codeforces Round #525 (Div. 2) C
思路:先给所有数加上一个较大的数M,再让每个数(a[i]+M)对(a[i]+M-i)取余即可
细节:之所以要加M,是因为i能取到1e5,所以要保证a[i]足够大,否则会出现对负数取模
#include<bits/stdc++.h> using namespace std; const int M = 100000; typedef long long ll; ll a[M]; int main() { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; cout << n + 1<<endl; cout << 1 << " " << n << " " << M <<endl; for (int i = 1; i <= n; i++) cout << 2 << " " << i << " " << M + a[i] - i << endl; return 0; }
知识点:n%(n-x)=x
总结:学到一个新的取余公式
总结:这次寒假接触了很多新的东西,kmp,欧拉降幂,树状数组等等,同时发现自己的局限性也很大,各种算法不熟悉,数据结构也几乎是一片空白,思维题没有思维,数学题也吃了数学不好的亏,cf排名一直在降,但是对于大一刚刚接触计算机的我来说,进步也不小了,但我不能满足于这点成就,身边就有很多比我厉害很多很多的人,要以他们为目标一直学习才行。寒假做过的题绝不止这上面的八题,但是这八题能体现出来寒假主要的收获,接下来的日子里要更多的练习和学习了。
心里有光,哪儿都美