注意一:当值作下标时注意是否越界
注意二:开静态数组时注意是1e5+3还是1e6+3
注意三:求和SUM时注意是否需要ull
A题:给出RGB三色块数,问能否排成一列且相邻块异色
解:如果有其中两个数之和比第三个数小2及以上则不能
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;cin>>t;
while(t--){
int r,g,b;
cin>>r>>g>>b;
if(r+g<b-1)cout<<"No"<<endl;
else if(r+b<g-1)cout<<"No"<<endl;
else if(g+b<r-1)cout<<"No"<<endl;
else cout<<"Yes"<<endl;
}
return 0;
}
B题:小明要依次背N首诗,每首诗用时Ai秒。妈妈听小明背诗,每背完一首得到一份礼物,但只听前S秒,现小明可以删一首诗不背,问他要得到最多礼物应删哪首诗,可不删
解:遍历一次,求前缀和同时维护当前出现的用时最长的诗的用时及下标
当前缀和大于S时,直接输出当前出现的用时最长的诗的下标
当前缀和等于S时,如果正好是最后一首,输出0,即不删;如果维护的用时最长的诗的用时比下一首诗的用时短则也是0,若是更长则输出用时最长的诗的下标
#include<bits/stdc++.h>
using namespace std;
int a[100003];
int main(){
int t;cin>>t;
while(t--){
int n,s;cin>>n>>s;
for(int i=1;i<=n;i++)cin>>a[i];
int tmp,sum=0,ans=0,mxv=-1;
for(int i=1;i<=n;i++){
tmp=a[i];sum+=tmp;
if(tmp>mxv){
ans=i;
mxv=tmp;
}
if(sum>s){
cout<<ans<<endl;
break;
}
if(sum==s){
if(i==n){
cout<<0<<endl;
break;
}
if(mxv<=a[i+1]){
cout<<0<<endl;
break;
}
cout<<ans<<endl;
break;
}
}
if(sum<s)cout<<0<<endl;
}
return 0;
}
C题:现有一堆礼物,以栈形式存放,按给定编号顺序拿出礼物,若编号i礼物是栈中从栈顶往下数第K+1个,则需要操作k+1次出栈和K次入栈共2K+1次操作,他上面的K个礼物的顺序在入栈时可以随意调动,问全部礼物拿出需要的最小总操作数
解:依次出拿礼物,维护前面已经访问到的最大深度,当当前要拿出的礼物的深度比原先的小,就直接ans++,因为他可以被放到栈顶,否则就是2*(深度值-i-1)+1;,即2K+1,此处的深夜K是深度值-i,i是轮数,从0起,第i轮时已有i个礼物被拿走,故是深度值-i
#include<bits/stdc++.h>
using namespace std;
int a[100003];
int main(){
int t;cin>>t;
while(t--){
int m,n,tmp,mx=0;
unsigned long long ans=0;
cin>>m>>n;
for(int i=1;i<=m;i++){
cin>>tmp;
a[tmp]=i;
}
for(int i=0;i<n;i++){
cin>>tmp;
if(a[tmp]>mx){
ans+=2*(a[tmp]-i-1)+1;
mx=a[tmp];
}
else ans++;
}
cout<<ans<<endl;
}
return 0;
}
D题:有N人,每人有N属性,现随机选两人(可重复),问第一人属性中随机选一个且第二人有的概率
解:求每个属性被抽到的概率,再每个属性有人拥有的概率(即有多少人有),得相乘之和
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const ull N=1e6+3,mod=998244353;
ull p[N],cnt[N],inv[N];
int main(){
inv[1]=1;for(ull i=2;i<N;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
ull n;cin>>n;
for(ull i=1;i<=n;i++){
ull m;cin>>m;
ull x=1LL*inv[n]*inv[m]%mod;
for(ull j=1;j<=m;j++){
ull tmp;cin>>tmp;
cnt[tmp]++;
p[tmp]=(p[tmp]+x)%mod;
}
}
ull ans=0;
for(ull i=1;i<N;i++)ans=(ans+p[i]*cnt[i]%mod*inv[n]%mod)%mod;
cout<<ans<<endl;
return 0;
}
补充:快递幂求逆元
#include <iostream>
using namespace std;
ll fmx(ll a,ll p,ll mod){
a%=mod;
ll ans=1;
while(p){
if(p&1)ans=(ans*a)%mod;
a=(a*a)%mod;
p>>=1;
}
return ans;
}
int main(){
ll a,p,mod;cin>>a>>p>>mod;
cout<<fmx(a,p,mod)<<endl;//求a^p模mod
cout<<fmx(a,mod-2,mod)<<endl;//求a^(p-2)模mod这,就是模mod意义下a的逆元
return 0;
}
补充:两个不等长有序数组的中位数求法
int find_median(int *A,int *B,int m,int n,int s,int t){
int p=(s+t)/2,c=(m+n-1)/2;/* 有多少个数小于下中位数 */
if(s>t)return find_median(B,A,n,m,0,n-1);/* 如果下中位数不在A中,就从数组B找 */
else if(A[p]>=B[c-p-1]&&A[p]<=B[c-p])return A[p];/* 数组A中有p个数小于A[p], 当且进当数组B中有c-p个数小于A[p], A[p]才是中位数 */
else if(A[p]<B[c-p-1])return find_median(A,B,m,n,p+1,t);/* A[p]太小了,从数组A中找一个更大的数尝试 */
else return find_median(A,B,m,n,s,p-1);/* A[p]太大了,从数组A中找一个更小的数尝试 */
}
int main(){
int A[]={1,3,5,7,9};
int B[]={2,4,6,8,10};
int m = sizeof(A)/sizeof(int);
int n = sizeof(B)/sizeof(int);
printf("%d\n", find_median(A, B, m, n, 0, m-1));/* 从数组A和B中找下中位数 */
return 0;
}