2020牛客寒假算法基础集训营2 题解
A-做游戏(思维)
ans=min(A,X)+min(B,Y)+min(C,Z)
#include<iostream> #include<algorithm> using namespace std; typedef long long ll; ll min(ll a,ll b){ if(a>b) return b;return a;} ll a[3],b[3]; int main() { for(int i=0;i<3;i++) scanf("%lld",&a[i]); for(int i=0;i<3;i++) scanf("%lld",&b[i]); ll ans=min(a[0],b[1])+min(a[1],b[2])+min(a[2],b[0]); cout<<ans<<endl; }
B-排数字(思维题)
最佳的排列方法为616161616.....,设字符串中1的个数为x,6的个数为y,当y≥2的时候ans=min(y-1,x)
#include<iostream> #include<algorithm> using namespace std; const int maxn=2e5+10; char s[maxn]; int main() { int n,x=0,y=0; scanf("%d%s",&n,s); for(int i=0;i<n;i++){ if(s[i]=='6') x++; else if(s[i]=='1') y++; } int ans=0; if(x>=2) ans=min(x-1,y); cout<<ans<<endl; }
G-判正误(快速幂)
直接计算mod1e9+7意义下等式左边的值判断是否等于右边即可
#include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int mod=1e9+7; ll pow(ll a,ll b) { ll res=1; while(b){ if(b&1) res=(a*res)%mod; b>>=1; a*=a; a%=mod; } return res; } int main() { int n; scanf("%d",&n); while(n--){ ll a,b,c,d,e,f,g; cin>>a>>b>>c>>d>>e>>f>>g; ll ans=pow(a,d)%mod; ans+=pow(b,e)%mod; ans+=pow(c,f)%mod; if(ans==g) cout<<"Yes"<<endl; else cout<<"No"<<endl; } }
D-数三角(计算几何)
枚举三个顶点,判断两条边的点积是否小于0即可,注意判断三点共线的情况
#include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int maxn=505; ll n,x[maxn],y[maxn]; bool judge(int a,int b,int c) { if((x[a]*y[b]-x[b]*y[a]+x[b]*y[c]-x[c]*y[b]+x[c]*y[a]-x[a]*y[c])==0) return false; return (x[b]-x[a])*(x[c]-x[a])+(y[b]-y[a])*(y[c]-y[a])<0; } int main() { scanf("%lld",&n); ll ans=0; for(int i=0;i<n;i++) scanf("%lld%lld",&x[i],&y[i]); for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ for(int k=j+1;k<n;k++){ if(judge(i,j,k)||judge(j,k,i)||judge(k,i,j)) ans++; } } } cout<<ans<<endl; return 0; }
C-算概率(概率)
设f[i][j]为做i道题对j题的概率,①当j>0时,fi,j = fi-1,j * ( 1 - p[i] ) + fi-1,j-1 * p[i] ②当j=0时,fi,j = fi-1,j * ( 1 - p[i] )
#include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int maxn=2005; const int mod=1e9+7; ll p[maxn],f[maxn][maxn]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&p[i]); f[0][0]=1; for(int i=1;i<=n;i++){ f[i][0]=f[i-1][0]*(mod+1-p[i])%mod; for(int j=1;j<=n;j++) f[i][j]=f[i-1][j]*(mod+1-p[i])%mod+(f[i-1][j-1]*p[i])%mod; } for(int i=0;i<=n;i++) cout<<f[n][i]%mod<<" "; }
E-统计数(数学)
对等式两边同时平方 : i + j + 2 * sqrt( i * j) =k,这样我们发现 i * j必须是完全平方数的时候才可以,因此我们枚举完全平方数,再枚举其因子数即可,每次都加2(因为 (2,8,4) 跟 (8,2,4)算两个)最后还要再减去1(减去(4,4,4)这种情况),
#include<iostream> #include<algorithm> #include<cmath> using namespace std; int main() { int n,ans=0; scanf("%d",&n); for(int i=1;i<=sqrt(n);i++){ for(int j=1;j<=i;j++) if(i*i%j==0) ans+=2; ans--; } cout<<ans<<endl; }
F-拿物品(思维题,排序)
直接按照两物品的和排序依次输出即可
#include<iostream> #include<algorithm> using namespace std; const int maxn=2e5+10; struct node{ int a,b,sum,pos; }a[maxn]; int cmp(node x,node y){return x.sum>=y.sum;} int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i].a),a[i].pos=i; for(int i=1;i<=n;i++) scanf("%d",&a[i].b),a[i].sum=a[i].a+a[i].b; sort(a+1,a+1+n,cmp); for(int i=1;i<=n;i+=2) cout<<a[i].pos<<" "; cout<<endl; for(int i=2;i<=n;i+=2) cout<<a[i].pos<<" "; }
H-施魔法(DP)
先将数组排序,数组被连续的分成几段取完代价才能最小
定义 f i为取完前i个元素的花费
维护 的前缀最小值就能O(1)转移了。
#include<iostream> #include<algorithm> using namespace std; const int maxn=3e5+7; int a[maxn],dp[maxn],pre,k,n; int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+1+n); pre=-a[1]; for(int i=1;i<k;i++) dp[i]=2e9; for(int i=k;i<=n;i++){ dp[i]=pre+a[i]; pre=min(pre,dp[i-k+1]-a[i-k+2]); } cout<<dp[n]<<endl; }
J-求函数(线段树)
题解链接:https://www.cnblogs.com/overrate-wsj/p/12274408.html
I-建通道(思维)
思路:对于相同的元素,连接起来的代价为0,所以我们可以先将所有元素去重。去重之后,我们从低到高遍历每个数字的每一位(二进制意义下),找到所有数字中既有0又有1的一位,将边将在0与1之间,这样的代价肯定是最小的
#include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int maxn=2e5+10; ll a[maxn]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); sort(a+1,a+1+n); int len=unique(a+1,a+1+n)-(a+1); for(int i=0;i<=30;i++){ ll ans=1<<i; int x=0,y=0; for(int j=1;j<=len;j++){ if((a[j]>>i)&1) x++; else y++; } if(x&&y){ ans*=(ll)(len-1); cout<<ans<<endl; return 0; } } cout<<0<<endl; return 0; }