听了偶像的话,决定也来写一写题解哈哈哈~
可能编码风格不是很好orz
题解写得不好!凑合着看吧~
A水题
将一个正实数四舍五入。
因为输入的浮点数长度小于等于2000,已经超过了double的数据范围,所以我是用字符串做的。
先判断是否存在小数点,不存在的话直接输出。
存在的话判断小数点后一位的数是否大于等于5来决定是否进位。
char s[maxn]; void solve() { scanf("%s",s); int pos=-1,len=strlen(s); rep(i,0,len-1)if(s[i]=='.')pos=i; if(pos==-1) { printf("%s ",s); return; } if(s[pos+1]<'5') { rep(i,0,pos-1)printf("%c",s[i]); puts(""); return; } pos--; rep(i,0,pos)s[i]-='0'; bool ju=0; s[pos]++; int pp=pos; while(1) { if(s[pp]>=10) { s[pp]%=10; if(!pp) { ju=1;break; } s[--pp]++; continue; } break; } if(ju)printf("1"); rep(i,0,pos)printf("%c",s[i]+'0'); }
给你两个数组a,b。
让你有多少种取法使得从a中取一个数ai,从b中取一个数bj使得ai+bj是一个质数。
我是先求出200000内的质数,然后记录b中每个数出现的次数。
a数组记录个数去重,枚举a。
int pri[maxn],cnt; bool vis[maxn]; void init() { for(int i=2;i<maxn;i++) { if(!vis[i])pri[++cnt]=i; for(int j=1;j<=cnt&&pri[j]*i<maxn;j++) { vis[i*pri[j]]=1; if(i%pri[j]==0)break; } } } int n,m,a[maxn],b,cntb[maxn],cnta[maxn],ma; ll res; void solve() { init(); sdd(n,m); rep(i,1,n)sd(a[i]),cnta[a[i]]++; rep(i,1,m)sd(b),cntb[b]++,ma=max(ma,b); sort(a+1,a+1+n); n=unique(a+1,a+1+n)-a-1; rep(i,1,n) { int k=upper_bound(pri+1,pri+1+cnt,a[i])-pri,sum=0; rep(j,k,cnt) { if(pri[j]-a[i]>ma)break; sum+=cntb[pri[j]-a[i]]; } res=res+1ll*cnta[a[i]]*sum; } plld(res); }
不管a的话题意相当于:有n座山,第i做山的高度为hi,小C只能从当前位置i移动到右边的位置j,且该位置的高度比原位置的高度大。即i<j&&hi<hj,需要花费的体力值为hj*(j-i+1)
然后有q个询问,每个询问给x,w。x代表起始位置,w代表小C的体力值,问小C能到达的最大位置。
最开始看错题意(傻
把hj*(j-i+1)理解成hj*(j-i)
做法:先预处理,以每个点为起点,求每一个它到能到达的位置需要的体力值。可能会出现当前位置pos到x<y,但是到x的体力值比到y的体力值花费大。so~
int n,q; int a,xx,h[maxn]; ll x[maxn][maxn]; vector<PLI >vec[maxn],ans[maxn]; PII p[maxn]; int cnt; void solve() { sdd(n,q); rep(i,1,n)sdd(a,xx),h[a]=xx; rep(i,1,n)//起点 { cnt=0; rep(j,i+1,n)//终点 { if(h[j]<=h[i])continue; ll mi=1ll*h[j]*(j-i+1); rep(k,i+1,j-1) { if(h[k]>h[i]&&h[j]>h[k])mi=min(mi,x[i][k]+1ll*h[j]*(j-k+1)); } x[i][j]=mi; vec[i].pb(mk(x[i][j],j)); } sort(vec[i].begin(),vec[i].end()); int si=vec[i].size(); if(si)ans[i].pb(vec[i][0]); rep(j,1,si-1) { if(vec[i][j].se<ans[i].back().se)continue; ans[i].pb(vec[i][j]);//puts("?"); // pdd(i,vec[i][j].se); } } while(q--) { int x,w; sdd(x,w); int k=upper_bound(ans[x].begin(),ans[x].end(),mk(1ll*w,n+1))-ans[x].begin(); if(!k)pd(x); else pd(ans[x][k-1].se); } }
(怎么有点懒得写了orz
D(不会qwq
E(水题
记录质数,然后记录位置是质数的字符,C,S,U出现的次数
int pri[maxn],cnt; bool vis[maxn]; void init() { for(int i=2;i<maxn;i++) { if(!vis[i])pri[++cnt]=i; for(int j=1;j<=cnt&&pri[j]*i<maxn;j++) { vis[i*pri[j]]=1; if(i%pri[j]==0)break; } } } char str[maxn]; int c,s,u; void solve() { init(); sc(str+1); int len=strlen(str+1); rep(i,2,len) { if(!vis[i]) { if(str[i]=='S')s++; if(str[i]=='C')c++; if(str[i]=='U')u++; } } if(c>=2&&s&&u)puts("Yes"); else puts("No"); }
F
给你一个序列,让你求最长的完美子序列长度
一个序列是完美的:对于所有的1<=i<n,满足b[i]不是b[i + 1]的因数。
做法:预处理每个数的因子fac,然后对于第i个数,求前边i-1个数中不是ai的因子且长度最长的长度,我是用线段树做的,找到两个相邻因子中间的数的最大长度。
vector<int>fac[maxn]; void init() { rep(i,1,maxn-5) { for(int j=1;j*j<=i;j++) { if(i%j==0) { fac[i].pb(j); if(j*j!=i)fac[i].pb(i/j); } } sort(fac[i].begin(),fac[i].end()); } } struct node{ int l,r; int ma; }a[maxn<<2]; int n; void build(int k,int l,int r) { a[k].l=l;a[k].r=r; if(l==r)return; int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void update(int k,int l,int x) { if(a[k].l==l&&a[k].r==l) { a[k].ma=x; return; } int mid=(a[k].l+a[k].r)>>1; if(l<=mid)update(k<<1,l,x); else update(k<<1|1,l,x); a[k].ma=max(a[k<<1].ma,a[k<<1|1].ma); } int query(int k,int l,int r) { if(l>r)return 0; if(a[k].l>=l&&a[k].r<=r)return a[k].ma; int mid=(a[k].l+a[k].r)>>1,ans=0; if(l<=mid)ans=query(k<<1,l,r); if(r>mid)ans=max(ans,query(k<<1|1,l,r)); return ans; } int ans; void solve() { init(); sd(n); build(1,1,1e5); rep(i,1,n) { int x; sd(x); int si=fac[x].size(),res=0; for(int i=0;i<si-1;i++) { res=max(res,query(1,fac[x][i]+1,fac[x][i+1]-1)); } res=max(res,query(1,x+1,1e5)); ans=max(ans,res+1); update(1,x,res+1); } pd(ans); }
G
算出的所有连续子序列中有多少满足:
1,所有数的和为k的倍数;
2,且其和至少为z;
记录前缀和%k的和,然后对于当前位置的sum,满足的是sum-sumi>=z,即sumi<=sum-z,看这个数在vec中的位置
int n,k,z,a[maxn]; vector<ll>vec[maxn]; ll res; void solve() { scanf("%d%d%d",&n,&k,&z); rep(i,1,n)sd(a[i]); // rep(i,0,k)vec[i].pb(0); vec[0].pb(0); ll sum=0; rep(i,1,n) { sum+=a[i]; int y=sum%k; if(sum<z) { vec[y].pb(sum); continue; } int pos=upper_bound(vec[y].begin(),vec[y].end(),sum-z)-vec[y].begin(); // cout<<i<<' '<<y<<' '<<pos<<endl;//' '<<vec[y][pos]<<endl; vec[y].pb(sum); res+=pos; } plld(res); }
H
哈希
给你两个字符串s和t,问你s中有多少个子串,而这个子串不是t的子串
(用map和unordered_map都超时了qwq
const ull base=233; int n,m; char s[maxn],t[maxn]; ull p[maxn],has1[maxn],has2[maxn]; void init() { p[0]=1; rep(i,1,max(n,m))p[i]=p[i-1]*base; rep(i,1,n)has1[i]=has1[i-1]*base+s[i]; rep(i,1,m)has2[i]=has2[i-1]*base+t[i]; } ull get1(int l,int r) { return has1[r]-has1[l-1]*p[r-l+1]; } ull get2(int l,int r) { return has2[r]-has2[l-1]*p[r-l+1]; } ull pp[maxn*maxn]; int res,cnt; void solve() { sdd(n,m); sc(s+1); sc(t+1); init(); rep(i,1,m)rep(j,i,m) { pp[++cnt]=get2(i,j); } sort(pp+1,pp+1+cnt); cnt=unique(pp+1,pp+1+cnt)-pp; rep(i,1,n)rep(j,i,n) { ull tmp=get1(i,j); int k=lower_bound(pp+1,pp+1+cnt,tmp)-pp; if(k>cnt||pp[k]!=tmp)res++;//,pdd(i,j); } pd(res); }
I
有一个n*m的矩阵,问你有多少种放法,使得每一行每一列最多只能放置一个
想法:对于n*m的矩阵,考虑第一行要不要放,放的话有m个位置,答案转移为m*dfs(n-1,m-1),即转化为(n-1)*(m-1)的矩阵的放法。
不放的话答案转移为dfs(n-1,m),即转化为(n-1)*m的矩阵的方法。
int n,m; int d[maxn][maxn]; int dfs(int nn,int mm) { if(nn>mm)swap(nn,mm); if(d[nn][mm])return d[nn][mm]; if(!nn)return 1; if(nn==1)return d[nn][mm]=mm+1; return d[nn][mm]=(1ll*mm*dfs(nn-1,mm-1)%mod+dfs(nn-1,mm))%mod; } void solve() { sdd(n,m); pd(dfs(n,m)); }
J(不会
K(不会
本来没想打的,但是无聊啊!敲了3个小时后就敲不出来了,然后就溜啦~