A: [Advanced Guide to Algorithmic Competition] A^B
Each integer can be uniquely expressed as the sum of the powers of 2 without repetition of several exponents.
For example, 3 ^ 5:5 can be expressed as 101,3 ^ (1 * 2 ^ 2 + 0 * 2 ^ 1 + 1 * 2 ^ 0)
#include <iostream> #include <algorithm> using namespace std; using ll = long long; // Counting int Pow(int a, int b, int p) { int ans = 1 % p; while (b != 0) { if (b & 1) ans = (ll)ans * a % p; a = (ll)a * a % p; b >>= 1; } return ans; } int main() { int a, b, p; cin >> a >> b >> p; cout << Pow(a, b, p) << endl; return 0; }
B: [Advanced Guide to Algorithmic Competition] 64-bit integer multiplication
Similar to fast power, the integer b is represented in binary.
For example: 3*5:3* (1*2^2+0*2^1+1*2^0)
long long mul(long long a, long long b, long long p) { long long ans = 0; for (; b; b >>= 1) { // From low to high if (b & 1) ans = (ans + a) % p; //This bit is 1, so it adds up. a = a * 2 % p; // On each bit, the corresponding a is the power of 2. } return ans; }
C : A^B II
The key to this question is to prevent data spillover, which is the same as fast power.
a * b % p = ( a % p ) * ( b % p ) % p;
D: [Algorithmic Competition Advanced Guide] Confused Switches
Binary operation, state compression
Enumerate the click status of all switches in the first line, and then recurse the status of its n-1 line
0 denotes points and 1 denotes no points
#include <iostream> #include <vector> using namespace std; const int INF = 0x3f3f3f3f; char a[5][6]; int b[5][5]; const int dis[4][2] = {0, 1, 1, 0, 0, -1, -1, 0}; void click(int x, int y) { b[x][y] ^= 1; for (int i = 0; i < 4; i++) { int dx = x + dis[i][0]; int dy = y + dis[i][1]; if (dx < 0 || dx >= 5 || dy < 0 || dy >= 5) continue; b[dx][dy] ^= 1; } } int main() { //freopen("test.txt","r",stdin); int t; cin >> t; while (t--) { for (int i = 0; i < 5; i++) cin >> a[i]; int ans = INF, cnt = 0, flag = 0; //ans represents the minimum number of steps, cnt records the current number of steps, flag indicates that the current solution is not feasible for (int i = 0; i < 32; i++) //Enumeration of 32 schemes { for (int k = 0; k < 5; k++) { // cout<<a[k]<<endl; for (int j = 0; j < 5; j++) b[k][j] = a[k][j] - '0'; } cnt = 0; flag = 0; for (int j = 0; j < 5; j++) { if ((i >> j) & 1) { cnt++; click(0, j); //Click on the switch in the first line } } for (int j = 0; j < 4; j++) //Fixed the first line of lights and changed the remaining four lines of lights. { for (int k = 0; k < 5; k++) { if (!b[j][k]) //If one of the lights in the previous row is off, turn the previous one on through the next row { cnt++; click(j + 1, k); } } } for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (!b[i][j]) //Traveling through all lights, if there are still lights, shows that this scheme is not feasible { flag = 1; break; } } if (flag) break; } if (!flag) //It shows that the scheme is feasible. { ans = min(ans, cnt); } } //cout<<ans<<endl; if (ans == INF || ans > 6) cout << -1 << endl; else cout << ans << endl; } return 0; }
E: The shortest way to get all keys
bfs+ like pressure
There are more states in this question. Each step needs to record the status of the current key, which can be expressed by binary 01.
struct Step { int x; int y; int ck; //The current state of the key in hand Step(int x,int y,int ck):x(x),y(y),ck(ck){} }; class Solution { public: queue<Step> que; bool vis[35][35][1<<7]={false}; //Mark whether the current state is extended const int dis[4][2]={0,1,1,0,0,-1,-1,0}; int shortestPathAllKeys(vector<string>& grid) { int len1=grid.size(); int len2=grid[0].length(); int k=0; //Record the number of keys for(int i=0;i<len1;i++) { for(int j=0;j<len2;j++) { if(grid[i][j]>='a'&&grid[i][j]<='z') k++; if(grid[i][j]=='@') { que.push(Step(i,j,0)); vis[i][j][0]=true; } } } int steps=0; while(!que.empty()) { int l=que.size(); while(l--) { Step u=que.front(); que.pop(); for(int i=0;i<4;i++) { int dx=u.x+dis[i][0]; int dy=u.y+dis[i][1]; int x=u.ck; //Take out the current state if(dx>=0&&dx<len1&&dy>=0&&dy<len2) { char ch=grid[dx][dy]; if(ch=='#'||vis[dx][dy][x]) continue; if(ch>='a'&&ch<='z') { x=x|(1<<(ch-'a')); //Change this bit to 1 if(x==((1<<k)-1)) { return steps+1; } } if(ch>='A'&&ch<='Z') { if(!(x>>(ch-'A')&1)) //Determine whether the current bit is 1? { continue; } } vis[dx][dy][x]=true; que.push(Step(dx,dy,x)); } } } steps++; //Step number plus 1 } return -1; } };
F: [Advanced Guide to Algorithmic Competition] Hamilton Path
Pressure dp
dp[i][j] denotes the shortest path from the starting point to point i, under the state j
State 0 denotes no passing and 1 denotes passing
For example, dp[3][13], state 13 is 1101 in binary, that is, it passes through point 2 from 0 to 3, but no more than 1
In the process of dp, which point is the shortest path from which to get to the point? I ^ 1 * j takes the state of the jth point back, that is to say, the jth point is from the state 0101.
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int INF=0x3f3f3f3f; int n; int weight[25][25]; //Save weight int dp[25][1<<20]; //dp[i][j] denotes that at point i, under the state j, the shortest path from the starting point to the point is dp[i][j] int findMin(int n) { memset(dp,INF,sizeof(dp)); dp[0][1]=0; //Starting point assignment, only through 0 path 0 for(int i=1;i<1<<n;i++) //Enumerate all states, in all states, the shortest path from the starting point to each point { for(int j=0;j<n;j++) { if(i&(1<<j)) //Remove the state of the j th point in the state i, if 1, indicating the passage { for(int k=0;k<n;k++) //Determine which points pass before j-point { // i ^ 1 * J reverses the j position of i in binary because it has not reached the J point before. if((i^1<<j)>>k&1) //Before passing through point j, whether it passes through point k, such as 1101, when it reaches point 2, whether it passes through point 0, 1, 3, this state means that it does not pass through point 1. { dp[j][i]=min(dp[j][i],dp[k][i^1<<j]+weight[j][k]); } } } } } return dp[n-1][(1<<n)-1]; } int main() { //freopen("test.txt","r",stdin); cin>>n; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { cin>>weight[i][j]; } } cout<<findMin(n)<<endl; return 0; }
H: [Advanced Guide to Algorithmic Competition] Laser Bomb
Two-dimensional prefix sum
5000 * 5000, card space, two two two-dimensional arrays will explode, can only use a two-dimensional array, save data points first, then directly sum.
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + dp[i][j];
Enumerate all squares with R edges
ans = max(ans, dp[i][j] - dp[i - m][j] - dp[i][j - m] + dp[i - m][j - m])
#include <iostream> #include <algorithm> #include <cstdio> #include <vector> using namespace std; const int MAXN = 5005; // int a[MAXN][MAXN]; //Storage value int dp[MAXN][MAXN]={0}; //Store two-dimensional prefixes and int n, m; //n targets, bombs with m sides, r lengths, c widths int main() { // freopen("test.txt", "r", stdin); cin >> n >> m; int len1 = m; //That's ok int len2 = m; //column int x, y, k; //Coordinates, values for (int i = 1; i <= n; i++) { cin >> x >> y >> k; dp[x+1][y+1] +=k; //Value accumulation len1 = max(len1, x+1); len2 = max(len2, y+1); } for (int i = 1; i <= len1; i++) //Two-dimensional prefix sum, starting from 1, facilitates the summation of edge points. { for (int j = 1; j <= len2; j++) { dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + dp[i][j]; } } int ans = 0; for (int i = m; i <= len1; i++) { for (int j = m; j <= len2; j++) { ans = max(ans, dp[i][j] - dp[i - m][j] - dp[i][j - m] + dp[i - m][j - m]); } } cout << ans << endl; return 0; }
I: [Algorithmic Competition Advanced Guide] Inc Sequence
Difference
The same sequence, indicating that the difference between the last two numbers is 0, can be converted to difference so that the final sequence is 0.
#include <iostream> #include <cmath> #include <algorithm> using namespace std; using ll = long long; ll nums[100005]; ll dp[100005]; int main() { int t; cin >> t; for (int i = 1; i <= t; i++) { cin >> nums[i]; dp[i] = nums[i] - nums[i - 1]; } ll s1 = 0, s2 = 0; for (int i = 2; i <= t; i++) { if (dp[i] > 0) s1 += dp[i]; //Number of times you need to subtract 1 else s2 -= dp[i]; //Number of times you need to add 1 } cout << max(s1, s2) << endl; cout << abs(s1 - s2) + 1 << endl; return 0; }
J: Heating
Dichotomy finds the shortest distance from each house to the nearest heating, and finally maximizes all distances
#include <iostream> #include <algorithm> #include <vector> using namespace std; const int INF=0x3f3f3f3f; class Solution { private: int n, m; vector<long long> Heaters; vector<long long> Houses; public: Solution(int n, int m) { this->n = n; this->m = m; } void addHouses(int x) { Houses.push_back(x); } void addHeaters(int x) { Heaters.push_back(x); } int finfRadius() { sort(Heaters.begin(),Heaters.end()); long long ans = 0; for (int i = 0; i < Houses.size(); i++) { long long cur = INF; // Returns the first iterator no less than x auto l = lower_bound(Heaters.begin(), Heaters.end(), Houses[i]); if (l != Heaters.end()) //There is heating on the right side of the house. { cur = *l - Houses[i]; } if (l != Heaters.begin()) //There is heating on the left side of the house. { auto s = l - 1; //Left Heating Position cur = min(cur, Houses[i] - *s); //The one with the smallest distance } ans = max(cur, ans); } return ans; } }; int n, m; int main() { freopen("test.txt","r",stdin); cin >> n >> m; Solution sol(n, m); for (int i = 0; i < n; i++) { long long a; cin >> a; sol.addHouses(a); } for (int j = 0; j < m; j++) { long long a; cin >> a; sol.addHeaters(a); } cout << sol.finfRadius() << endl; return 0; }
K: Linear sieve primes
Template use
#include <iostream> #include <algorithm> #include <cstdio> #include <vector> #include <cstring> using namespace std; const int MAX_N = 10000001; int v[MAX_N], prime[MAX_N]; //Prime arrays store prime numbers, and v arrays mark them. void primes(int n) { memset(v, 0, sizeof(v)); // Minimum prime factor int m = 0; // Prime number for (int i = 2; i <= n; i++) { if (v[i] == 0) { // i is prime number. v[i] = i; prime[++m] = i; } // Multiply the current number i by a prime factor for (int j = 1; j <= m; j++) { // i has a smaller prime factor than prime[j], or is beyond the range of n if (prime[j] > v[i] || prime[j] > n / i) break; // prime[j] is the minimum prime factor of the sum i*prime[j] v[i * prime[j]] = prime[j]; } } } int n, m; int main() { // freopen("test.txt","r",stdin); cin >> n >> m; primes(n); while (m--) { int t; cin >> t; if (t == v[t]) cout << "Yes" << endl; else cout << "No" << endl; } return 0; }
L: [Advanced Guide to Algorithmic Competition] Best Cattle Fence
M: [Blue Bridge Cup] [Successive Examinations] Maximum Submatrix
Dimensional Reduction Dynamic Programming
Enumeration of all possible combinations, cumulative by column, into one-dimensional maximum subordination and problem
Finding the Maximum Subordinate Sum
class Solution { public: int maxSubArray(vector<int>& nums) { vector<int> dp(nums.size(),0); int m=0,maxn=nums[0]; for(int i=0;i<nums.size();i++) { if(m>0) m+=nums[i]; //m is a positive number and then adds else m=nums[i]; //If m is a negative number, don't add it, because the negative number will pull down the nums[i] value. maxn=max(maxn,m); } return maxn; } };
Dynamic programming approach
-1 -4 3 3 4 -1 -5 -2 8
#include <iostream> #include <algorithm> #include <cstdio> #include <vector> using namespace std; int findMax(int *arr,int n) //Conversion to the one-dimensional problem of finding the maximum sum of subordinates { int maxn=arr[0],m=0; for(int i=0;i<n;i++) { if(m>0) m+=arr[i]; else m=arr[i]; if(maxn<m) maxn=m; } return maxn; } int dp[505][505]; int arr[505]; int main() { // freopen("test.txt","r",stdin); int n,m; cin>>n>>m; for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { cin>>dp[i][j]; } } //Enumerate all combinations int maxn=dp[0][0]; for(int i=0;i<n;i++) { fill(arr,arr+n,0); //Clear 0 at a time for(int j=i;j<m;j++) { for(int k=0;k<n;k++) arr[k]+=dp[k][j]; //Cumulative k row j column int m=findMax(arr,n); maxn=max(m,maxn); } } cout<<maxn<<endl; return 0; }
Prefix and + lis
#include <iostream> #include <algorithm> #include <cstdio> #include <vector> using namespace std; int dp[505][505]; //DP [i] [j]: prefix and int n, m; const int INF = 0x3f3f3f3f; int main() { // freopen("test.txt","r",stdin); cin >> n >> m; int maxSum = -INF; bool flag = false; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cin >> dp[i][j]; if (dp[i][j] < 0) { maxSum = max(maxSum, dp[i][j]); } else flag = true; //Incomplete dp[i][j] += dp[i - 1][j]; } } if (flag == false) cout << maxSum << endl; else { int ans = 0; for (int i = 1; i <= n; i++) //Enumerate all possible combinations { for (int j = i; j <= n; j++) { int maxn = 0; for (int k = 1; k <= m; k++) { maxn += (dp[j][k] - dp[i - 1][k]); if (maxn < 0) maxn = 0; ans = max(maxn, ans); } } } cout << ans << endl; } return 0; }