2019牛客国庆集训派对day6 A(规律,十进制快速幂) B(概率) C(思维模拟) G(思维)H(思维) J(贪心)

A.2016(规律,十进制快速幂)

题目链接:A.2016

题意:

     给出二维矩阵求 A的n次方, (1≤n<10^100000)

解题思路:

   由于n很大,题目中有关键提示:

Feel free to think why the problem is called `2016`,所以此题的运算应该与2016有关,具体怎么推出来的我也不太清楚 ,欢迎指教

做法一:

#include<iostream>
#include<string>
using namespace std;
int main(){
   string s;
   int a, a1, a2, b, b1, b2, c, c1, c2, d, d1, d2, i, n;
   cin >> s;
   n = 0;
   int len = s.size(); 
   for(i = 0; i < len; i++){
      n = (n*10 + (s[i] - '0'))%2016;
   }
   cin >> a >> b >> c >> d;
   if(n == 0){
      a = 1; b = 0; c = 0; d = 1;
   }
   a1 = a; b1 = b; c1 = c; d1 = d;
   for(i = 1; i < n; i++){
      a2 = a; b2 = b; c2 = c; d2 = d;
      a = (a1 * a2 + b1 * c2) % 7;
      b = (a1 * b2 + b1 * d2) % 7;
      c = (c1 * a2 + d1 * c2) % 7;
      d = (c1 * b2 + d1 * d2) % 7;
   }
   cout << a << " " << b << endl;
   cout << c << " " << d << endl;
   return 0;
}

做法二:十进制快速幂

#include <bits/stdc++.h>
using namespace std;
 
#define LL long long
#define MAXN 100005
#define mod 7
char str[MAXN];
struct mat{
   int m[3][3];
}base,ans;
mat multiply(mat a,mat b){
   mat temp;
   for(int i = 0; i < 2; i++){
      for(int j = 0; j < 2; j++){
         temp.m[i][j] = 0;
         for(int k = 0; k < 2; k++){
         	temp.m[i][j]=(temp.m[i][j] + a.m[i][k] * b.m[k][j]) % mod;
			}
      }
	}
   return temp;
}
mat quick_mod(LL n){
   ans.m[0][0] = ans.m[1][1] = 1;
   ans.m[1][0] = ans.m[0][1] = 0;
   while(n){
      if(n&1)
         ans = multiply(ans,base);
        base = multiply(base,base);
        n >>= 1;
   }
   return ans;
}
int main(){
   int num;
   while(scanf("%s", str)!=EOF){
      num = 0;
      int len = strlen(str);
      for(int i = 0; i < len; i++)
         num=(num * 10 + str[i] - '0') % 2016;
      scanf("%d%d",&base.m[0][0], &base.m[0][1]);
      scanf("%d%d",&base.m[1][0], &base.m[1][1]);
      base = quick_mod(num);
      printf("%d %d\n",base.m[0][0], base.m[0][1]);
      printf("%d %d\n",base.m[1][0], base.m[1][1]);
   }
   return 0;
}

B.Gambling

题目链接:B.Gambling

题意:

     给a个红色气球,b个绿色气球,c个蓝色气球,不放回的取,取出全部红色气球得一等奖,取出全部绿色气球得二等奖,取出全部蓝色气球得三等奖。问获得一等奖的概率,获得二等奖的概率,获得三等奖的概率

解题思路:

  

#include<cstdio>
#include<algorithm>
using namespace std;
long long x, y, z;
void cal(long a, long b, long c, int p) {
    x = b * c * (2 * a + b + c);
    y = (a + b + c) * (a + b) * (a + c);
    z = __gcd(x, y);
    printf("%lld/%lld%c", x / z, y / z, p < 3 ? ' ' : '\n');
}
int main() {
    long long a, b, c;
    scanf("%lld%lld%lld", &a, &b, &c);
    cal(a, b, c, 1);
    cal(b, a, c, 2);
    cal(c, a, b, 3);
    return 0;
}

C.Hamiltonian Path(思维模拟)

题目链接:C.Hamiltonian Path

题意:
     给n个点,m条边,求从1走到n的最短距离, 1只能走2,   2 只能走3,后面同理

解题思路:

    只需用一个数组记录从当前点到后一个点的最短距离,然后求和

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 5;
int a[maxn];
int main(){
	int n, m, ans = 0;
	cin >> n >> m;
	memset(a, INF, sizeof(a));
	for(int i = 1; i <= m; i++){
		int u, v, w;
		cin >> u >> v >> w;
		if(v - u == 1){         // 如果相差为1,则记录最短距离
			a[u] = min(a[u], w);
		}
	}
	for(int i = 1; i < n; i++){
		if(a[i] == INF){       // 此路不通
			cout << -1 << endl;
			return 0;
		}
		else{
			ans = ans + a[i];
		}
	}
	cout << ans << endl;
	return 0;
}

G.Rolling Variance(思维)

题目链接:G.Rolling Variance

题意:

    求相邻m个数的值,公式为

解题思路:

设平均值为b

化简sqrt(a[1] * a[1]  - 2 * a[1] * b + b * b +   a[2] * a[2] - 2 * a[2] * b + b * b + .......... + a[m] * a[m] - 2 * a[m] * b + b * b)/m-1

          = sqrt( a[1] * a[1] + a[2] * a[2] + ... + a[m] * a[m] + m * b * b -  2* b * (a[1] + a[2] + .... a[m] ))

这样只需求a[i] * a[i] 的前缀和,  a[i] 的前缀和就行

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
double a[maxn], b[maxn];
int main(){
	int n, m;
	cin >> n >> m;
	a[0] = 0;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
		b[i] = b[i-1] + a[i] * a[i];
		a[i] = a[i] + a[i-1];
	}
	for(int i = m; i <= n; i++){
		double k = a[i] - a[i-m];
		double ab = k / m;
		double fang = b[i] - b[i-m];
		cout << sqrt((fang + (double)m * ab * ab - 2 * k * ab ) / (double)(m - 1)) << endl;
	}
	return 0;
}

H.Super Fast Fourier Transform(思维)

题目链接:H.Super Fast Fourier Transform

题意:

    给出两个数组。

(a[i], b[i] ≥ 0,a[1] + a[2]+⋯+a[n],  b[1] + b[2]+…,b[m] ≤ 10^6)

解题思路:

   由给出的数据范围,分析出数组a和数组b中会出现相当多重复的数字,所以不必一个一个加,只需判断个数,相同的乘以数量即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6 + 5;
ll a1[maxn], b1[maxn];
ll a[maxn], b[maxn];
int main(){
	ll n, m, k, len1 = 1, len2 = 1;
	cin >> n >> m;
	for(int i = 1; i <= n; i++){
		cin >> k;
		if(a[k] == 0){
			a1[len1] = k;
			len1++;
		}
		a[k]++;
	}
	for(int j = 1; j <= m; j++){
		cin >> k;
		if(b[k] == 0){
			b1[len2] = k;
			len2++;
		}
		b[k]++;
	}
	ll ans = 0;
	for(int i = 1; i < len1; i++){
		for(int j = 1; j < len2; j++){
			ans += (ll)sqrt(abs(a1[i] - b1[j])) * a[a1[i]] * b[b1[j]];
		}
	}
	cout << ans << endl;
	return 0;
}

J.Defense Tower(贪心)

题目链接: J.Defense Tower

题意:

   给出n个防御塔的伤害值,n-1条边(代表哪两个防御塔相邻),需要摧毁所有防御塔,攻击当前防御塔,当前的防御塔不会攻击你,而和此防御塔相邻的塔会攻击你。求摧毁所有防御塔受到的最小伤害。

解题思路:

    想要摧毁所有防御塔,一定会受到n-1次攻击,那么只要先攻击防御塔伤害最高的,那么他就不会打你,然后依次更新被攻击掉的和他相邻的防御塔伤害就可以

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
struct node{
	int val, pos;
}a[maxn];
ll sum[maxn];   // 攻击此防御塔会受到的伤害
bool cmp(node k, node u){
	return k.val > u.val;
}
vector<int> ve[maxn];
int main(){
	int n, ans = 0;
	cin >> n;
	for(int i = 1; i <= n; i++){
		cin >> a[i].val;
		a[i].pos = i;
	}
	for(int i = 1; i < n; i++){
		int v, u;
		cin >> v >> u;
		ve[u].push_back(v);
		ve[v].push_back(u);
		sum[v] += a[u].val;
		sum[u] += a[v].val;
	}
	sort(a+1, a+1+n, cmp);
	for(int i = 1; i <= n; i++){
		ans += sum[a[i].pos];
		int len = ve[a[i].pos].size();
		for(int j = 0; j < len; j++){
			sum[ve[a[i].pos][j]] -= a[i].val;
		}
	}
	cout << ans << endl;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
牛客 a卷2022年第四季度的华为题目中,要求考生设计一种高效的数据结构,能够支持以下几种操作: 1. 添加一个元素 2. 删除一个元素 3. 查找是否存在某个元素 4. 返回元素的总数 该数据结构要求满足空间复杂度较小、时间复杂度较低、能够快速地进行查找和修改等多种操作。 想要编写这样一种数据结构,我们可以参考许多已有的经典算法与数据结构,如二叉树、哈希表、红黑树等,通过综合利用它们的优点来实现这个问题的解决。 例如,我们可以通过哈希表来存储所有元素的值,并在每个哈希链表的元素中再使用红黑树来进行排序与查找。这样,我们既能够轻松地进行元素的添加和删除操作,也能够在查找较大数据范围和数量时保持较高的速度与效率。同时,由于使用了多个数据结构来协同完成这个问题,我们也能够在空间复杂度上适度地进行优化。 当然,在具体设计这个数据结构的过程中,我们还需要考虑一些实践中的细节问题,例如如何避免哈希冲突、如何处理数据丢失与被删除元素所占用的空间等问题,这都需要相应的算法与流程来进行处理。 总体来看,设计这种支持多种操作的高效数据结构,需要我们具备丰富的算法知识和编程实践能力,同时需要我们在具体处理问题时能够将多种算法和数据结构进行有效地结合。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值