2020牛客寒假算法基础集训营1
这套题整体来说还是很简单的。
这个题目不是很难,不过要考虑周全,面积是1,那么底边的长度可以是1也可以是2,
注意底边1和2会有重复的,所以要注意去除这个重复部分的。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+10; typedef long long ll; const int mod=1e9+7; int main(){ ll n,m,ans=0; scanf("%lld%lld",&n,&m); ans=2*(m-2)%mod*m%mod*(n-1)%mod; ans+=2*(n-2)%mod*n%mod*(m-1)%mod; ans+=2*(m-1)%mod*(m-2)%mod*(n-2)%mod; ans+=2*(n-1)%mod*(n-2)%mod*(m-2)%mod; ans%=mod; printf("%lld\n",ans); return 0; }
这个题目也很简单,因为每一个音符的概率都是确定的。。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+10; typedef long long ll; int main(){ int n,x,a,b; cin>>n>>x>>a>>b; double ans=n*x*a+n*(100-x)*b; ans/=100.0; printf("%.2f\n",ans); return 0; }
这个可能看起来稍微复杂一点,不过整体还是很简单,
把所有可以投影到y轴的投影到y轴,可以投影到x轴的投影到x轴。
然后排个序,求长度最短的n-k个点。
#include<bits/stdc++.h> using namespace std; const int maxn=3e5+10; typedef long long ll; long double dx[maxn],dy[maxn]; long double x[maxn],y[maxn]; int judge(ll x,ll y){ if(x>0&&y>0) return 1; if(x<0&&y>0) return 2; if(x<0&&y<0) return 3; if(x>0&&y<0) return 4; } int main(){ ll n,k; long double x0,y0; scanf("%Lf%Lf%lld%lld",&x0,&y0,&n,&k); int f=judge(x0,y0); int num=0,numx=0,numy=0; for(int i=1;i<=n;i++){ scanf("%Lf%Lf",&x[i],&y[i]); int ans=judge(x[i],y[i]); if(ans==f) num++; else if(x0*x[i]>0) numx++; else if(y0*y[i]>0) numy++; } if(num+numx>k&&num+numy>k){ printf("-1\n"); return 0; } int cntx=0,cnty=0; for(int i=1;i<=n;i++){ if(x[i]*x0<0){ // cout<<"i="<<i<<" x[i]="<<x[i]<<" y[i]="<<y[i]<<endl; dy[++cnty]=(y0-y[i])/(x0-x[i])*(-x0)+y0; // printf("dy[%d]=%Lf\n",cnty,dy[cnty]); } if(y0*y[i]<0){ dx[++cntx]=(x0-x[i])/(y0-y[i])*(-y0)+x0; } } int res=n-k; sort(dy+1,dy+1+cnty); sort(dx+1,dx+1+cntx); long double ans=2e9; for(int i=res;i<=cntx;i++){ // printf("dx[%d]=%Lf\n",i,dx[i]); ans=min(ans,dx[i]-dx[i-res+1]); } for(int i=res;i<=cnty;i++){ // printf("dy[%d]=%Lf dy[%d]=%Lf\n",i,dy[i],i-res+1,dy[i-res+1]); ans=min(ans,dy[i]-dy[i-res+1]); } printf("%.6Lf\n",ans); return 0; }
这个太签到了
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+10; typedef long long ll; int vis[maxn]; int main(){ int n; scanf("%d",&n); for(int i=1;i<n;i++){ int x; scanf("%d",&x); vis[x]=1; } for(int i=1;i<=n;i++){ if(!vis[i]){ printf("%d\n",i); return 0; } } }
这个题目f函数其实求的就是约数的个数,这个还是很好求的,
把这个数唯一分解,x=p1^a1*p2^a2*....*pn^an
那么这个数的约数的个数就是 num=(a1+1)*(a2+1)*...*(an+1)
这个就暴力求就可以了。
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+10; typedef long long ll; const int mod=1e9+7; ll v[maxn],isp[maxn],m; void init1() { for(int i=2;i<maxn;i++){ if(v[i]==0){ isp[m++]=i; v[i]=i; } for(int j=0;j<m;j++){ if(v[i]<isp[j]||i*isp[j]>maxn) break; v[i*isp[j]]=isp[j]; } } } ll judge(ll x){ ll ans=1,p=1; for(int i=0;i<m;i++){ while(x%isp[i]==0){ // printf("isp[%d]=%d\n",i,isp[i]); p++,x/=isp[i]; } ans*=p,p=1; if(x==1) break; } if(x>1) ans*=2; // printf("x=%lld ans=%lld\n",x,ans); return ans; } int main(){ init1(); ll n,res=0; scanf("%lld",&n); while(n>2) n=judge(n),res++; printf("%lld\n",res); return 0; }
这个题目我觉得我写的挺复杂的,
我是先预处理出白色块的连通块。
然后对于每一个黑块去枚举它周围的白色连通块。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+10; typedef long long ll; struct node{ int v,nxt; node(int v=0,int nxt=0):v(v),nxt(nxt){} }e[maxn*2]; int head[maxn],cnt; void add(int u,int v){ e[++cnt]=node(v,head[u]); head[u]=cnt; e[++cnt]=node(u,head[v]); head[v]=cnt; } int f[maxn],sum[maxn]; char s[maxn]; void dfs(int u,int pre){ f[u]=pre,sum[u]=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].v; if(v==pre) continue; dfs(v,u); if(s[u]!='B'&&s[v]!='B') sum[u]+=sum[v]; } } void dfs1(int u,int pre){ for(int i=head[u];i;i=e[i].nxt){ int v=e[i].v; if(v==pre) continue; if(s[u]!='B'&&s[v]!='B') sum[v]=max(sum[v],sum[u]); dfs1(v,u); } } ll ans=0; void dfsans(int u,int pre){ for(int i=head[u];i;i=e[i].nxt){ int v=e[i].v; if(v==pre) continue; dfsans(v,u); } if(s[u]!='B') return ; ll all=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].v; if(s[v]=='B') continue; all+=sum[v]; ans-=sum[v]*(sum[v]-1)/2; } ans+=all*(all-1)/2; } int main(){ int n; scanf("%d%s",&n,s+1); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v); } dfs(1,-1),dfs1(1,-1); dfsans(1,-1); printf("%lld\n",ans); }
这个题目很简单,直接暴力枚举26个字母即可。
#include<bits/stdc++.h> #define inf 0x3f3f3f3f using namespace std; const int maxn=2e5+10; typedef long long ll; char s[maxn]; int num[30],pos[30][maxn]; int main(){ int n,k; scanf("%d%d%s",&n,&k,s+1); int slen=strlen(s+1); for(int i=1;i<=slen;i++){ int x=s[i]-'a'; num[x]++; pos[x][num[x]]=i; } int ans=inf; for(int i=0;i<26;i++){ if(num[i]<k) continue; int cnt=0; for(int j=k;j<=num[i];j++) ans=min(ans,pos[i][j]-pos[i][j-k+1]+1); } if(ans>=inf) ans=-1; printf("%d\n",ans); return 0; }
这个是一个二分,二分最大长度即可。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+10; typedef long long ll; const int mod=1e9+7; char s[maxn]; int n,k,slen; int num[2][maxn]; bool check(int x){ for(int i=x;i<=slen;i++){ int len0=num[0][i]-num[0][i-x]; int len1=num[1][i]-num[1][i-x]; if(len0<=k||len1<=k) return true; } return false; } int main(){ scanf("%d%d%s",&n,&k,s+1); slen=strlen(s+1); for(int i=1;i<=slen;i++){ num[0][i]=num[0][i-1]; num[1][i]=num[1][i-1]; num[s[i]-'0'][i]++; } int l=0,r=n,ans=0; while(l<=r){ int mid=(l+r)>>1; if(check(mid)) ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",ans); return 0; }
这个是一个dp,注意细节的处理。
#include<bits/stdc++.h> using namespace std; const int maxn=3e5+10; typedef long long ll; char cur[]={'n','i','c','o'},s[maxn]; ll dp[maxn]; int main(){ ll n,a,b,c; scanf("%lld%lld%lld%lld%s",&n,&a,&b,&c,s+1); for(int i=1;i<=n;i++){ dp[i]=max(dp[i-1]+a,dp[i]); if(i>=2) dp[i]=max(dp[i],dp[i-2]+b); if(i>=3) dp[i]=max(dp[i],dp[i-3]+c); } ll ans=0; int num=0,pos=0,slen=strlen(s+1); s[++slen]='~'; for(int i=1;i<=slen;i++){ if(s[i]==cur[pos]) { pos++; if(pos==4) num++,pos=0; } else{ ll res=dp[num]; if(pos>=2){ if(num>=1) res=max(dp[num-1]+b,res); if(num>=2) res=max(dp[num-2]+c,res); } ans+=res,num=0,pos=0; if(s[i]==cur[pos]) pos++; } } printf("%lld\n",ans); return 0; } /* 19 1 2 5 niconiconiniconico */
这个推一下就会发现,x和y的指数都是斐波那契数列的一项,a^b的指数是斐波那契数列的前缀和。
所以都可以用矩阵快速幂解决,斐波那契数列前缀和也可以用矩阵快速幂解决。
但是这个还有几个点需要注意,第一个:斐波那契数列求的是指数,所以不可以直接对mod取模,而是要对mod-1取模,因为费马小定理。
ap-1 mod p == 1 所以只可以对p-1取模。
第二个就是a是p的倍数时,不满足费马小定理,这个要分开考虑。
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; const long long mod = 1e9+7; int UP; struct mat { long long mn[10][10]; mat() { for(int i = 0;i<UP;i++) { for(int j = 0;j<UP;j++) { mn[i][j]=0; } } for(int i = 0;i<UP;i++) { mn[i][i] = 1; } } void init(){ for(int i=0;i<UP;i++){ for(int j=0;j<UP;j++){ mn[i][j]=0; } } } mat operator * (const mat& a) { mat res; for(int i = 0;i<UP;i++) { res.mn[i][i] = 0; } for(int i=0;i<UP;i++) { for(int j=0;j<UP;j++) { for(int k=0;k<UP;k++) { res.mn[i][j] += mn[i][k]*a.mn[k][j]%(mod-1); res.mn[i][j] %= (mod-1); } } } return res; } }; mat fast(mat a,long long c) { mat res = mat(); while(c) { if(c&1) res = res * a; a = a*a; c >>= 1; } return res; } ll quick_mul(ll a,ll b,ll mod) { ll ans = 0; while(b) { if (b & 1) ans = (ans + a) % mod; a = (a + a) % mod; b >>= 1; } return ans; } ll quick_pow(ll a,ll b,ll mod) { ll ans = 1; while(b) { if (b & 1) ans = quick_mul(ans, a, mod); a = quick_mul(a, a, mod); b >>= 1; } return ans; } int main(){ UP=2; ll n,x,y,a,b; scanf("%lld%lld%lld%lld%lld",&n,&x,&y,&a,&b); if(n==1) { printf("%lld\n",x%mod); return 0; } if(n==2){ printf("%lld\n",y%mod); return 0; } if(x%mod==0||y%mod==0||a%mod==0){ printf("0\n"); return 0; } mat res;res.init(); res.mn[1][1]=0,res.mn[0][0]=res.mn[0][1]=res.mn[1][0]=1; res=fast(res,n-2); x=quick_pow(x,res.mn[1][0],mod); y=quick_pow(y,res.mn[0][0],mod); a%=mod,a=quick_pow(a,b,mod); UP=3,res.init(); res.mn[0][1]=res.mn[1][0]=res.mn[1][1]=1; res.mn[2][0]=res.mn[2][1]=res.mn[2][2]=1; res=fast(res,n-3); a=quick_pow(a,res.mn[2][1]+res.mn[2][2],mod); printf("%lld\n",quick_mul(quick_mul(a,x,mod),y,mod)); return 0; }
来源:https://www.cnblogs.com/EchoZQN/p/12272902.html