听说是队长 WongDark 出的题😱,emmmm 好简单??😰
7-1.简单数学题
1 2 3 4 5 6 7 8 9 10 #include <bits/stdc++.h> using namespace std ;signed main () { long long a,b; cin >>a>>b; cout <<__gcd(a,b)<<endl ; return 0 ; }
7-2.拿子游戏
思路 :巴什博奕——对于当前局势的可以取的 n , m 来说 n %(m+1)== 0
后手必胜,否则先手必胜
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <bits/stdc++.h> using namespace std ;int main () { int t;cin >>t; while (t--){ int n,m; scanf ("%d%d" ,&n,&m); if (n % (m+1 ) !=0 ) printf ("yE5\n" ); else printf ("n0\n" ); } return 0 ; }
7-3.数塔问题
题意 :如下图所示为一个数塔,从数塔的顶层出发,在每一个结点可以选择向左走或者向右走,一直走到最底层。要求找出一条路径,使得路径上的数值和最大。
上图所示的数塔中,最大路径和为 1+2+3+2+1=9
思路 :经典数塔问题 ,区别在于这个做了一个变式还有 n-1 层的递减,只需要处理好由下向上的转移方程就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <bits/stdc++.h> using namespace std ;typedef long long ll;int n;ll dp[505 ][505 ]; signed main () { ios::sync_with_stdio(false ),cin .tie(0 ); cin >>n; for (int i=1 ;i<=n;++i) for (int j=1 ;j<=i;++j) cin >>dp[i][j]; for (int i=n+1 ;i<=2 *n-1 ;++i) for (int j=1 ;j<=2 *n-i;++j) cin >>dp[i][j]; for (int i=2 *n-2 ;i>=n;--i) for (int j=1 ;j<=2 *n-i;++j) dp[i][j]+=max(dp[i+1 ][j-1 ],dp[i+1 ][j]); for (int i=n-1 ;i>=1 ;--i) for (int j=1 ;j<=i;++j) dp[i][j]+=max(dp[i+1 ][j],dp[i+1 ][j+1 ]); cout <<dp[1 ][1 ]<<endl ; return 0 ; }
7-4.飞机探测
思路 :洛谷变式题 ,分治法经典题
7-5.王的疑惑
题意 :国王想要修路使任意两个城市都可以互相到达(可以直接也可以间接),国王希望修建的道路尽可能的少,请回答他修路的最高花费和最低花费的差值
思路 :就是求最大生成树和最小生成树的权值和之差
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include <bits/stdc++.h> using namespace std ;#define int long long int n,m;int fa[200005 ];struct node { int x,y,v; }road[500005 ]; bool cmp1 (node x,node y) { return x.v<y.v; } bool cmp2 (node x,node y) { return x.v>y.v; } void init () { for (int i=1 ;i<=n;i++) fa[i]=i; } int find (int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void join (int x,int y) { int fx=find(x),fy=find(y); if (fx==fy) return ; else { fa[fy]=fx; } } signed main () { ios::sync_with_stdio(false ),cin .tie(0 ); while (cin >>n>>m){ init(); for (int i=1 ;i<=m;i++) cin >>road[i].x>>road[i].y>>road[i].v; sort(road+1 ,road+1 +m,cmp1); int sum1=0 ,sum2=0 ; for (int i=1 ;i<=m;i++){ if (find(road[i].x)!=find(road[i].y)){ sum1+=road[i].v; join(road[i].x,road[i].y); } } init(); sort(road+1 ,road+m+1 ,cmp2); for (int i=1 ;i<=m;i++){ if (find(road[i].x)!=find(road[i].y)){ sum2+=road[i].v; join(road[i].x,road[i].y); } } cout <<sum2-sum1<<endl ; } return 0 ; }
7.6-任务分配
思路 :因为数据很小所以可以直接搜索,保证在矩阵中选的 n 个元素任意两个没有处于同一行(一个任务只能分配给一个人)或者同一列(一个人只能被分配一个任务)即可。但是需要剪枝:一是维护一个最小值 minn
每次搜索过程中就超过最小值没必要继续当前的搜索,其次还需要再进行一个剪枝就是维护每个任务的分配最小值的后缀和,当后面没搜索的加上这个后缀和都大于 minn
那也没必要继续当前搜索了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <bits/stdc++.h> using namespace std ;typedef long long ll;int n;int ans;int m[25 ][25 ];bool vis[25 ];int minn[25 ];void dfs (int step, int cost) { if (step >= n + 1 ) { ans = min(ans, cost); return ; } for (int i = 1 ; i <= n; ++i) { if (vis[i] == 0 ) { if (m[step][i] + cost >= ans) continue ; if (m[step][i] + cost + minn[step + 1 ] >= ans) continue ; vis[i] = 1 ; dfs(step + 1 , m[step][i] + cost); vis[i] = 0 ; } } } signed main () { ios::sync_with_stdio(false ), cin .tie(0 ); cin >> n; for (int i = 1 ; i <= n; ++i) for (int j = 1 ; j <= n; ++j) cin >> m[i][j]; for (int i=n;i>=1 ;--i){ int p=0x3f3f3f3f ; for (int j=1 ;j<=n;++j){ p=min(p,m[i][j]); } minn[i]+=minn[i+1 ]+p; } ans = 0x3f3f3f3f ; dfs(1 , 0 ); cout << ans << endl ; return 0 ; }
7-7.国王的奖励
题意 :求一个等比数列 qn 的和,由于结果可能很大最后对 1e8+7 取模
思路:
当 q==1
时就是 n 个 1 相加,但是注意 n 的数据范围,答案也需要取模
当 q!=1
时利用求和公式,但是由于需要取模(除法不满足模运算),利用逆元将公式转换为乘法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <bits/stdc++.h> using namespace std ;typedef long long ll;const ll mod = 100000007 ;inline ll read () { ll s = 0 , w = 1 ; char c = getchar(); for (; !isdigit (c); c = getchar()) if (c == '-' ) w = -1 ; for (; isdigit (c); c = getchar()) s = (s << 1 ) + (s << 3 ) + (c ^ 48 ); return s * w; } ll quick_pow (ll a, ll b) { ll res = 1 , base = a % mod; while (b) { if (b & 1 ) res = (base * res) % mod; base = (base * base) % mod; b >>= 1 ; } return res; } ll inv (ll a) { return quick_pow(a, mod - 2 ) % mod; } signed main () { ios::sync_with_stdio(false ), cin .tie(0 ); int t; t = read(); while (t--) { ll q, n; q = read(), n = read(); if (q == 1 ) { cout << n % mod << endl ; continue ; } q %= mod; ll a = quick_pow(q, n) % mod; cout << (((a - 1 ) % mod) * (inv(q - 1 ) % mod)) % mod << endl ; } return 0 ; }
7-8.起泡排序
思路:冒泡排序本质是大小逆序的数交换,所以得到最终结果一定是每个逆序对都发生了交换。那么这题饶了半天就是让我们求一下这个序列的逆序数和,由于元素范围很大还需要利用一下离散化。求逆序数可以用树状数组或者权值线段树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <bits/stdc++.h> using namespace std ;#define int long long const int maxn=2e5 +5 ;int n;int a[maxn];int c[maxn];struct node { int val,id; }in[maxn]; int lowbit (int i) { return i&(-i); } void update (int i,int k) { while (i<=n){ c[i]+=k; i+=lowbit(i); } } int getsum (int i) { int res=0 ; while (i>0 ){ res+=c[i]; i-=lowbit(i); } return res; } bool cmp (node a,node b) { return a.val<b.val; } signed main () { while (cin >>n&&n){ for (int i=1 ;i<=n;i++){ cin >>in[i].val; in[i].id=i; } sort(in+1 ,in+n+1 ,cmp); for (int i=1 ;i<=n;i++) a[in[i].id]=i; memset (c,0 ,sizeof (c)); long long ans=0 ; for (int i=1 ;i<=n;i++){ update(a[i],1 ); ans+=i-getsum(a[i]); } cout <<ans<<endl ; } return 0 ; }
7.9大师的比试
思路:经典贪心题,为了在固定的时间内多比几场所以将时间段的结束时间从早到晚排序。当时间段的结束时间相同时,为了避免时间段重叠所以将时间段的开始时间从晚到早排序,然后按照排好序的时间走一遍统计能进行的比试。同时因为数据范围太大只能用 string 存储还需要写一个大数比较的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <bits/stdc++.h> using namespace std ;typedef long long ll;int n;struct node { string l, r; } m[10005 ]; bool cal (string a, string b) { int lena = a.length(), lenb = b.length(); if (lena != lenb) return lena < lenb; for (int i = 0 ; i < min(lena, lenb); ++i) { if (a[i] == b[i]) continue ; else return a[i] < b[i]; } return 1 ; } bool cmp (node a, node b) { if (a.r != b.r) return cal(a.r, b.r); return cal(b.l, a.l); } signed main () { ios::sync_with_stdio(false ), cin .tie(0 ); cin >> n; for (int i = 1 ; i <= n; ++i) cin >> m[i].l >> m[i].r; sort(m + 1 , m + 1 + n, cmp); int cnt = 0 ; string t = "0" ; for (int i = 1 ; i <= n; ++i) { if (cal(t, m[i].l)) { ++cnt; t = m[i].r; } } cout << cnt << endl ; return 0 ; }