2021BJTU新生赛预选赛题解


Problem A

  题意:二维平面中有一个地球E和一个二向箔V,V每次绕自己扩展一圈,求多少次后到达地球。

  题解:输出E和V横坐标差与纵坐标差中最大的即可。

  代码:

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 
 5 int T;
 6 int n, m;
 7 signed main() {
 8     int a, b, c, d;
 9     cin>>n>>m;
10     for(int i = 1;i<=n;++i) {
11         for(int j = 1; j<=m;++j){
12             char s;
13             cin>>s;
14             if(s == 'E') {
15                 a = i;
16                 b = j;
17             }
18             if( s== 'V') {
19                 c = i;
20                 d= j;
21             }
22         }
23     }
24     int l = abs(a-c);
25     int r = abs(b-d);
26     int ans = max(l,r);
27     cout<<ans;
28     return 0;
29 }

 

Problem B

  题意:储藏仓初始位置为0,初始能量为0,每一点能量能使储藏仓移动距离1。有n个核弹,第i个核弹在坐标为xi的位置,有vi的推动力。如果储藏仓经过xi,那么该位置核弹会给储藏仓增加vi点能量值。Q次询问,每次询问一个正整数k,询问储藏仓能否移动到坐标为k的位置。输入保证xi递增,第一个核弹在位置0。

  题解:记录ans为当前能到达的最远距离,输入核弹的x和v时,若x<=ans,那么ans+=v。询问时,判断k是否小于等于ans即可。

  代码:

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int maxn = 1e5+1000;
 5 int T;
 6 int n, m;
 7 signed main() {
 8     cin>>n;
 9     int ans = 0;
10     for(int i = 1, p, v; i <= n; ++i) {
11         scanf("%lld%lld", &p, &v);
12         if(p<=ans) ans+=v;
13     }
14     cin>>m;
15     for(int i = 1; i <= m; ++i) {
16         int query;
17         scanf("%lld" ,&query);
18         if(query<= ans) printf("Yes\n");
19         else printf("No\n");
20     }
21     return 0;
22 }

 

Problem C

题意:两群人分别有n个人和m个人。现有两个智子,每个智子监控其中一群人,但一共只能监控p个人。求方案数。(对13331取模)

题解:用两层循环,i、j,分别表示从第一群人中选i个人,第二群人中选j个人,要保证i+j小于等于p,然后用组合数求方案数。最后要减1,即减去选了0个人方案。组合数用递推公式预处理即可。

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int mod = 13331;
 5 int T;
 6 int n, m, p;
 7 int C[1010][1010];
 8 signed main() {
 9     cin>>n>>m>>p;
10     C[0][0] = 1;
11     for(int i = 1; i<= 1000;++i)
12         for(int j = 0;j<=1000;++j) 
13             if(j == 0) C[i][j] = 1;
14             else C[i][j] = C[i-1][j]+C[i-1][j-1]%mod;
15     int ans = 0;
16     for(int i = 0; i <= min(p,n); ++i) {
17         for(int j = 0; j<=min(p-i,m);++j) {
18             ans += C[n][i]*C[m][j]%mod;
19         }
20     }
21     ans--;
22     ans = (ans+mod)%mod;
23     cout<<ans;
24     return 0;
25 }

 

 

Problem D

题意:在Problem C的基础上,有k(k <= 1e5)个智子来监控k群人,第i群人有ai个人(Σai <= 1e6)。一共只能监控p个人,求方案数。(对998244353取模)

题解:设总人数为sum。因为每个人都是独立不重复的,那么答案就是C(sum, 1)+C(sum, 2)+C(sum, 3)+.....(It's just a joke)

代码:

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int mod = 998244353;
 5 const int maxn = 1e6+100;
 6 int T;
 7 int n, m, p, k, ans;
 8 int f[maxn], inv[maxn];
 9 int sum;
10 int ksm(int a, int b){
11     int ans = 1;
12     while(b) {
13         if(b&1) ans=(ans*a)%mod;
14         a =  a * a%mod;
15         b>>=1;
16     }
17     return ans;
18 }
19 int C(int sum,int to) {
20     f[0] = 1;
21     for(int i = 1 ;i<=sum;++i) f[i] = i*f[i-1]%mod;
22     inv[sum] = ksm(f[sum], mod-2);
23     for(int i = sum - 1; i >= 0; --i) inv[ i ] = inv[i+1] * (i + 1) % mod;
24     for(int i = 1;i<=to;++i) {
25         ans = (ans+f[sum]*inv[i]%mod*inv[sum-i])%mod;
26     }
27     return ans;
28 }
29 signed main() {
30     cin>>k;
31     for(int i = 1; i<=k;++i){
32         int a;
33         scanf("%lld", &a);
34         sum +=a;
35     }
36     cin>>p;
37     cout<<C(sum, min(sum, p));
38     return 0;
39 }

 

Problem E

题意:游戏赢一局得1分,输一局得-1分。连赢三局时,赢一局得2分。赢一局得概率是a / b。k (k <= 1000)次询问,每次询问求 n (n <= 1e9)局后期望得分(对19260817取模)。

题解:找规律。设赢一局概率p。n = 1时,期望得分是2*p-1。n = 2时,期望得分是4*p-2。n = 3时,期望得分是p*p*p +6*p - 3。n = 4时,期望得分是2*p*p*p +8*p - 4。那么猜测答案是(n-2)*p*p*p +n(2p - 1)。打表发现确实是这样(我这个憨憨最开始式子推错了,所以是嗯打表找出来的规律)。

代码:

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int mod = 19260817;
 5 int T;
 6 int ans;
 7 int n, a, b;
 8 int inv,win;
 9 int ksm(int a, int b){
10     int ans = 1;
11     while(b) {
12         if(b&1) ans=(ans*a)%mod;
13         a =  a * a%mod;
14         b>>=1;
15     }
16     return ans;
17 }
18 signed main() {
19     cin>>T;
20     while(T--) {
21         ans = 0;
22         scanf("%lld%lld%lld", &n, &a, &b);
23         inv = ksm(b, mod-2);
24         win = a * inv % mod;
25         if(n == 1) ans = (2 * win - 1)%mod;
26         else if(n == 2) ans = (4*win - 2)%mod;
27         else {
28             int base = (win*win%mod*win%mod)%mod;
29             ans = (base * (n-2))%mod;
30             ans = (ans+ n * (2*win - 1)%mod)%mod;
31         }
32         printf("%lld\n", ans);
33     }
34     return 0;
35 }

 

Problem F

题意:把一些数字的所有因数写在纸上,每张纸写一个因数,一共n (n <= 5000) 张纸。求出原来的那些数字。

题解:可以发现1的个数就是原来的数字的个数(虽然没什么用)。把所有因数从大到小排序,每取一个数,暴力往下删除它的所有因数。

代码:

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 
 5 int T;
 6 int n, m;
 7 int a[50500],ans[50050],vis[50050];
 8 int sum;
 9 int cnt;
10 signed main() {
11     cin>>n;
12     for(int i = 1; i<=n;++i) 
13         scanf("%lld", &a[i]);
14     sort(a+1, a+1+n);
15     int qwq = 0;
16     for(int i = n; i>=1; --i){
17         if(!vis[i]){
18             int last = 0;
19             ans[++qwq] = a[i];
20             for(int j = 1; j < i; ++j){
21                 if(a[j]!=last && !vis[j] && a[i]%a[j] == 0&& a[i]!=a[j]){
22                     last = a[j];
23                     vis[j] = 1;
24                 }
25             }
26         }
27     }
28     sort(ans+1, ans+1+qwq);
29     cout<<qwq<<endl;
30     for(int i = 1; i <= qwq; ++i)
31         printf("%lld ", ans[i]);
32     return 0;
33 }


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM