A
solution:
直接输出min(石头,剪刀) + min(剪刀,布) + min(布,石头)呗
std:
#include <bits/stdc++.h> using namespace std; #define ll long long int main() { ll a,b,c,d,e,f; cin>>a>>b>>c; cin>>d>>e>>f; cout<<min(a , e) + min(b , f) + min(c , d)<<endl; return 0; }
B
solution:
记录6和1的个数,最后输出min(1的个数,6的个数-1)即可
std:
#include <bits/stdc++.h> using namespace std; #define ll long long int main() { int n,cnt1 = 0,cnt6 = 0; string s; cin>>n>>s; for(int i=0;i<n;i++){ if(s[i] == '6') cnt6++; if(s[i] == '1') cnt1++; } cout<<min(cnt1 , cnt6 - 1)<<endl; return 0; }
C
solution:
设dp[i][j]代表前i道题做对了j道的概率,a[i]是第i道题做对概率,通项公式就是:
dp[i][j] = dp[i-1][j]×(mod - a[i] + 1) + dp[i-1][j-1]×a[i]
这大概是我仅能做出来的概率dp题了
std:
#include <bits/stdc++.h> using namespace std; #define ll long long const int maxn = 2002; const ll mod = 1e9+7; ll a[maxn]; ll dp[maxn][maxn]; int n; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { cin>>a[i]; } dp[0][0] = 1; for(int i=1;i<=n;i++){ dp[i][0] = dp[i-1][0]*(mod - a[i] + 1); dp[i][0] %= mod; for(int j=1;j<=i;j++){ dp[i][j] = dp[i-1][j]*(mod - a[i] + 1) + dp[i-1][j-1]*a[i]; dp[i][j] %= mod; } } for(int i=0;i<=n;i++){ if(i != 0) printf(" "); printf("%lld",dp[n][i]); } return 0; }
D
solution:
三层for循环,记得特判三个点共线!
std:
#include <bits/stdc++.h> using namespace std; #define ll long long const int maxn = 502; double a[maxn],b[maxn]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++){ cin>>a[i]>>b[i]; } int ans = 0; for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ for(int k=j+1;k<=n;k++){ int x = i, y = j ,z = k; double k1 = (a[x] - a[y])*(a[x] - a[y]) + (b[x] - b[y])*(b[x] - b[y]); double k2 = (a[x] - a[z])*(a[x] - a[z]) + (b[x] - b[z])*(b[x] - b[z]); double k3 = (a[y] - a[z])*(a[y] - a[z]) + (b[y] - b[z])*(b[y] - b[z]); double maxx = max(k1 ,max(k2 ,k3)); if(sqrt(k1) + sqrt(k2) + sqrt(k3) - sqrt(maxx) > sqrt(maxx) && k1 + k2 + k3 - maxx < maxx){ ans++; } } } } printf("%d\n",ans); return 0; }
E
solution:
两边平方一下就是i + j + 根号下(i*j) = k
题目要求i,j,k都是整数,所以i*j一定是一个平方数
所以我们只需要枚举根号下n的每一个数,求其平方数的所有因子
std:
#include <bits/stdc++.h> using namespace std; #define ll long long int main(){ int n,ans = 0; scanf("%d",&n); for(int i=1;i<=sqrt(n);i++) { int x = i*i; for(int j=1;j<=sqrt(x);j++){ if(x%j == 0){ int y = x/j; int z = j; if(y != z){ ans+=2; }else{ ans+=1; } } } } cout<<ans<<endl; return 0; }
F
solution:
题目说明牛牛和牛可乐都希望自己的得分尽量比对方大(最大化自己与对方得分的差)
牛牛实际得分 = 牛牛选择的物品和ai - 牛可乐选择的物品bi
牛可乐实际得分 = 牛可乐选择的物品和bi - 牛牛选择的物品和ai
计sum(a+b) 等于n个物品的ai+bi,将sum(a+b)分别加到他们的实际得分
牛牛得分 = sum(a) + 牛牛选择的物品ai + 牛牛选择的物品bi
牛可乐得分 = sum(b) + 牛可乐选择的物品bi + 牛可乐选择的物品ai
sum(a)和sum(b)都是定值,所以只需要将ai+bi从大到小排序,每个人依次取即可
std:
#include <bits/stdc++.h> using namespace std; #define ll long long const int maxn = 200005; ll a[maxn],b[maxn]; struct node{ ll x; int i; friend bool operator<(node p1,node p2){ return p1.x<p2.x; }//优先队列最da值优先 }; priority_queue<node> q;//优先较大队列 vector<int> v1,v2; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(int i=1;i<=n;i++){ scanf("%d",&b[i]); node now ; now.x = 1ll*(a[i] + b[i]); now.i = i; q.push(now); } int flag = 0; while(!q.empty()) { node now = q.top(); q.pop(); if(flag == 0){ flag = 1; v1.push_back(now.i); } else{ flag = 0; v2.push_back(now.i); } } for(int i=0;i<v1.size();i++){ if(i != 0) printf(" "); printf("%d",v1[i]); } printf("\n"); for(int i=0;i<v2.size();i++){ if(i != 0) printf(" "); printf("%d",v2[i]); } return 0; }
G
solution:
这是一道hash题~,取不同的mod执行快速幂,如果都相同说明猜想成立
std:
#include <bits/stdc++.h> using namespace std; #define ll long long const ll mod1 = 1e9+7; const ll mod2 = 1e9+9; ll mod; ll pow_mod(ll a,ll b) { ll ans = 1; while(b){ if(b&1) ans = ans*a%mod; a = a*a%mod; b>>=1; } return ans; } int main() { int t; cin>>t; while(t--) { ll a,b,c,d,e,f,g; int cnt = 0; cin>>a>>b>>c>>d>>e>>f>>g; mod = mod1; if(pow_mod(a,d) + pow_mod(b,e) + pow_mod(c,f) == g) cnt++; mod = mod2; if(pow_mod(a,d) + pow_mod(b,e) + pow_mod(c,f) == g) cnt++; if(cnt == 2){ printf("Yes\n"); continue ; } printf("No\n"); } return 0; }
H
solution:
DP 为什么这么简单的dp我又没想明白呢,菜
先将元素按能量值排序,可证明存在一个最优方案,满足每个魔法消耗一段连续的元素。
因为要求至少取 k 段,那么只能从 k+1 开始DP
定义dp[i]代表:前i项最优解,那么可以得到转移方程:
1.是前面的,从长度m变成m+1;
2.断开前面,从当前位置往前 k−1 项,和当前第 i 项,组成长度为 k 的序列。
std:
#include <bits/stdc++.h> using namespace std; #define ll long long const int maxn = 300005; ll a[maxn],dp[maxn]; int main() { int n , k; scanf("%d %d",&n,&k); for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); } sort(a+1,a+1+n); for(int i=1;i<k;i++) dp[i] = 1e10; ll pre = dp[0] - a[1]; for(int i=k;i<=n;i++){ dp[i] = pre + a[i]; pre = min(pre , dp[i-k+1] - a[i-k+2]); } printf("%lld\n",dp[n]); return 0; }
I
solution:
这一题我因为没有乘个数wa了。。。。赛后过题,菜
考虑二进制贪心,二进制的异或,如果对于n个数,考虑每个数的二进制,从最低位往高位枚举,如果这n个数的第i位二进制存在既有1又有0,那么我们就将所有的第i位是0的和第i位是1的相连就行,这样保证答案最小
std:
#include <bits/stdc++.h> using namespace std; #define ll long long const int maxn = 200005; ll a[maxn]; int b[maxn][40]; map<ll ,int> mp; int main() { int n,cnt = 0; ll x; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lld",&x); if(mp[x] == 1){ continue ; } mp[x] = 1; a[++cnt] = x; } if(cnt == 1){ cout<<"0"<<endl; return 0; } for(int i=1;i<=cnt;i++) { ll x = a[i]; int z = 0; while(x) { int y = x%2; x /= 2; b[i][++z] = y; } } ll ans; set<int> s; for(int i=1;i<=33;i++) { s.clear(); for(int j=1;j<=cnt;j++) { int x = b[j][i]; s.insert(x); } if(s.size() >= 2){ ans = 1ll*(1<<(i-1)); break ; } } cout<<ans*1ll*(cnt - 1)<<endl; return 0; }