[Codeforces] Round #352 (Div. 2)
人生不止眼前的狗血,还有远方的狗带
A题B题一如既往的丝帛题
A题题意:询问按照12345678910111213...的顺序排列下去第n(n<=10^3)个数是多少
题解:打表,输出
1 #include<bits/stdc++.h> 2 using namespace std; 3 int dig[10],A[1005]; 4 int main(){ 5 int aa=0; 6 for(int i=1;;i++){ 7 int x=i,dd=0; 8 while(x)dig[++dd]=x%10,x/=10; 9 for(int j=dd;j;j--) 10 A[++aa]=dig[j]; 11 if(aa>=1000)break; 12 } 13 int n; 14 scanf("%d",&n); 15 printf("%d\n",A[n]); 16 return 0; 17 }
B题题意:对于一个由小写字母组成的字符串s(|s|<=10^5),每次可以把一个字母改写成任意一个字母,
求使得这个序列没有重复子串的最小操作次数,若不存在输出-1
题解:因为单个字母也是子串,所以问题即为把一个字符串全部改成不同字母的最少步数
因为只有26个字母,所以若|s|>26则输出-1,否tong[i]表示第i个字母出现了几次,ans=sigma(max(tong[i]-1,0))
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,tong[26]; 4 char s[100005]; 5 int main(){ 6 scanf("%d%s",&n,s); 7 if(n>26)puts("-1"); 8 else{ 9 for(int i=0;i<n;i++) 10 tong[s[i]-'a']++; 11 int ans=0; 12 for(int i=0;i<26;i++) 13 if(tong[i])ans+=tong[i]-1; 14 printf("%d\n",ans); 15 } 16 return 0; 17 }
C题思路很简单,然而细节狗带
C题题意:二维平面上有n个(n<=10^5)点(xi,yi),有两个起点A(ax,ay)和B(bx,by),一个终点T(tx,ty)(0<=横纵坐标<=10^9)
可以从两个起点中的一个或两个出发,经过所有(xi,yi),且每到达一个(xi,yi)都要回到终点,问所有走过距离的最小值
题解:其实使距离改变的只有最开始的经过的第一个的点,及经过该点的方式
对于每个点,我们计算到T的距离tdi,到A的距离adi,和到B的距离bdi
然后把make_pair(adi-tdi,i),和make_pair(bdi-tdi,i)分别放到两个数组里排序
表示从A点或B点直接到达第一个点然后回到T使总距离减小了adi-tai或bdi-tai
然后就是分类讨论,细节见代码QwQ
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define pb push_back 4 #define mp make_pair 5 #define fir first 6 #define sec second 7 vector<pair<double,int> >haha[2]; 8 double x[3],y[3],tmp[3]; 9 double sq(double a){ return a*a; } 10 double pdd(double x1,double y1,double x2,double y2){ 11 return sqrt(sq(x1-x2)+sq(y1-y2)); 12 } 13 int main(){ 14 for(int i=0;i<3;i++) 15 scanf("%lf%lf",&x[i],&y[i]); 16 int n; 17 scanf("%d",&n); 18 double ans=0,xx,yy; 19 for(int i=1;i<=n;i++){ 20 scanf("%lf%lf",&xx,&yy); 21 for(int j=0;j<3;j++) 22 tmp[j]=pdd(x[j],y[j],xx,yy); 23 for(int j=0;j<2;j++) 24 haha[j].pb(mp(tmp[j]-tmp[2],i)); 25 ans+=tmp[2]*2; 26 } 27 for(int i=0;i<2;i++) 28 sort(haha[i].begin(),haha[i].end()); 29 if(haha[0][0].fir<0&&haha[1][0].fir<0){ 30 double Min; 31 if(haha[0][0].sec==haha[1][0].sec) 32 Min=min(haha[0][0].fir+min(0.0,haha[1][1].fir),min(0.0,haha[0][1].fir)+haha[1][0].fir); 33 else Min=haha[0][0].fir+haha[1][0].fir; 34 printf("%.12lf\n",ans+Min); 35 } 36 else printf("%.12lf\n",ans+min(haha[0][0].fir,haha[1][0].fir)); 37 return 0; 38 }
刀题懵逼,没有想到最关键的地方
刀题题意:给定一个长度为n(n<=5*10^5)的序列,每次操作把最大值-1,最小值+1,有多个则随机选一个中
求k(k<=10^9)次操作之后序列最大值与最小值的差
题解:真-最关键的地方:可以把最大值-1和最小值+1操作分开做
然后就没有然后了
1 By Ngshily_, contest: Codeforces Round #352 (Div. 1), problem: (B) Robin Hood, Accepted, # 2 3 #include<bits/stdc++.h> 4 using namespace std; 5 typedef long long ll; 6 #define maxn 500005 7 int n; 8 ll k,c[maxn]; 9 void solve(){ 10 sort(c+1,c+1+n); 11 ll tmp=k,lst=c[n]; 12 for(int i=2;i<=n;i++){ 13 ll delt=(c[i]-c[i-1])*(i-1); 14 if(delt<=tmp)tmp-=delt; 15 else{ lst=c[i-1]; break; } 16 } 17 int pos=0; 18 while(pos+1<=n&&c[pos+1]<=lst)pos++; 19 int shang=tmp/pos,yu=tmp%pos; 20 for(int i=1;i<=pos;i++) 21 c[i]=lst+shang+(i<=yu); 22 } 23 int main(){ 24 scanf("%d%I64d",&n,&k); 25 for(int i=1;i<=n;i++) 26 scanf("%I64d",&c[i]); 27 solve(); 28 for(int i=1;i<=n;i++)c[i]=-c[i]; 29 solve(); 30 sort(c+1,c+1+n); 31 printf("%I64d\n",c[n]-c[1]); 32 return 0; 33 }
E题题意:给定一个长度为n(n<=2*10^5)的序列A(ai<=2*10^5),设f[i][j]表示去掉[i,j]中的元素的序列中两数gcd的最大值,
求sigma(sigma(f[i][j]))
若我们求出了H[i]表示gcd<i的序列的个数,就可以轻易了www
要求H数组我们可以从大到小枚举一个divsor,通过如下方法求出H[divsor]
设next[i]表示对于任意j>=next[i],f[i][j]<divsor的最小位置,即后面的值随便取都不会使f[i][j]>divsor
H[divsor]=sigma(n-next[i]+1)
然后我们需要考虑divsor到divsor-1时next数组的转移
首先预处理出pos数组,pos[i]表示包含i这个因子的数在序列中的位置的集合
假设pos[divsor-1]={p1,p2,p3...pk-1,pk}
显然我们保留的区间最多只能包含其中的一个数,则...分类讨论again,都是套路
用线段树维护next数组
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define lson rt<<1,l,mid 4 #define rson rt<<1|1,mid+1,r 5 typedef long long ll; 6 #define maxn 200005 7 ll sum[maxn<<2],mn[maxn<<2],mx[maxn<<2],cvr[maxn<<2],H[maxn]; 8 int n,A[maxn],L[maxn][2],R[maxn][2]; 9 void push_up(int rt){ 10 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 11 mn[rt]=min(mn[rt<<1],mn[rt<<1|1]); 12 mx[rt]=max(mx[rt<<1],mx[rt<<1|1]); 13 } 14 void push_now(int rt,int len,ll val){ 15 sum[rt]=val*len; 16 mn[rt]=mx[rt]=cvr[rt]=val; 17 } 18 void push_down(int rt,int l,int mid,int r){ 19 if(cvr[rt]){ 20 push_now(rt<<1,mid-l+1,cvr[rt]); 21 push_now(rt<<1|1,r-mid,cvr[rt]); 22 cvr[rt]=0; 23 } 24 } 25 void update(int rt,int l,int r,int ql,int qr,ll val){ 26 if(ql>r||qr<l||mn[rt]>val)return; 27 if(ql<=l&&qr>=r&&mx[rt]<=val){ 28 push_now(rt,r-l+1,val); 29 return; 30 } 31 int mid=(l+r)>>1; 32 push_down(rt,l,mid,r); 33 if(ql<=mid)update(lson,ql,qr,val); 34 if(qr>mid)update(rson,ql,qr,val); 35 push_up(rt); 36 } 37 int main(){ 38 scanf("%d",&n); 39 int Max=0; 40 for(int i=1;i<=n;i++){ 41 scanf("%d",&A[i]); 42 Max=max(Max,A[i]); 43 int x=sqrt(A[i]); 44 for(int j=1;j<=x;j++){ 45 if(A[i]%j==0){ 46 if(!L[j][0])L[j][0]=i; 47 else if(!L[j][1])L[j][1]=i; 48 R[j][1]=R[j][0],R[j][0]=i; 49 if(j*j!=A[i]){ 50 if(!L[A[i]/j][0])L[A[i]/j][0]=i; 51 else if(!L[A[i]/j][1])L[A[i]/j][1]=i; 52 R[A[i]/j][1]=R[A[i]/j][0],R[A[i]/j][0]=i; 53 } 54 } 55 } 56 } 57 for(int i=1;i<=n;i++) 58 update(1,1,n,i,i,i); 59 for(int i=Max+1;i;i--){ 60 if(L[i][0]!=R[i][0]){ 61 update(1,1,n,1,L[i][0],R[i][1]); 62 update(1,1,n,L[i][0]+1,L[i][1],R[i][0]); 63 update(1,1,n,L[i][1]+1,n,n+1); 64 } 65 H[i]=(ll)n*(n+1)-sum[1]; 66 } 67 ll ans=0; 68 for(int i=1;i<=Max;i++) 69 ans+=(H[i+1]-H[i])*i; 70 printf("%I64d\n",ans); 71 return 0; 72 }
就是这样,没有喵