A 题目链接
思路:一共有N个摊位,C头牛,将N个摊位序号排一下序(下标从1开始),第一头牛肯定在下标为1的摊位上。则二分取 mid(两头牛之间最大的最小距离-即答案),从下标2开始遍历N个摊位,若摊位序号减去前一个放牛的摊位序号temp大于等于mid,则将一头牛放进此摊位,用此mid可以放牛的总数量sum加1。遍历结束,若sum>=C,则左边界l=mid+1,否则右边界r=mid-1。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int qs=1e5+7; 5 const int inf=0x3f3f3f3f; 6 ll A[qs]; 7 ll n,m; 8 int main() 9 { 10 ll i,j,k,x,y; 11 scanf("%lld%lld",&n,&m); 12 for(i=1;i<=n;++i) scanf("%lld",&A[i]); 13 sort(A+1,A+1+n); 14 ll l=0,r=A[n]-A[1]; 15 ll mid; 16 while(l<=r) //l肯定小于等于r 17 { 18 ll sum=1; 19 x=1; //x记录前一个牛放的位置的下标 20 ll temp=A[x]; //temp记录前一个牛放的位置的序号 21 mid=(l+r)/2; //取中间值mid 22 while(sum<m) 23 { 24 for(i=x+1;i<=n;++i) { 25 if(A[i]-temp>=mid) 26 { 27 sum++; temp=A[i]; //将牛放到此处,可放置的牛数量加1,temp,x记录 28 x=i; break; 29 } 30 } 31 if(i>n) break; 32 } 33 if(sum<m) r=mid-1; 34 else l=mid+1; 35 // printf("r=%lld l=%lld\n",r,l); 36 } 37 mid=(l+r)/2; 38 // printf("r=%lld l=%lld\n",r,l); 39 cout<<mid<<endl; 40 return 0; 41 }
B 题目链接
思路:二分取删除次数mid,根据给的删除顺序依次删除原序列 s 中的字符(注意下标),判断删除mid次后的s字符串子序列是否包含要表示的字符串S即可
//刚开始一直以为这样遍历数组会超时没敢写2333
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int qs=2e5+7; 5 const int inf=0x3f3f3f3f; 6 ll A[qs]; 7 ll B[qs]; 8 map<ll,ll> mp; 9 vector<int> v,c; 10 bool u[qs]; 11 int main() 12 { 13 int i,j,k; 14 string s,S; 15 cin>>s; 16 cin>>S; 17 int n=s.size(); //n是s的长度 18 for(i=0;i<n;++i) cin>>A[i]; 19 int L=S.size(); //L是S的长度 20 int l=0,r=n-L; 21 int mid; 22 while(l<=r) 23 { 24 for(i=0;i<=n;++i) u[i]=true; //每次循环将每个下标标记为没用过 (true) 25 mid=(l+r)/2; 26 int flag=0; 27 for(i=0;i<mid;++i) 28 u[A[i]-1]=false; //将需要删除的下标标为用过(false) 29 j=0; 30 for(i=0;i<n;++i) 31 { 32 if(!u[i]) continue; 33 if(s[i]==S[j]) j++; 34 if(j>=L) //表示s子序列中存在S 35 { 36 flag=1; break; 37 } 38 } 39 // printf("l=%d r=%d\n",l,r); 40 if(flag) l=mid+1; 41 else r=mid-1; 42 } 43 mid=(l+r)/2; 44 cout<<mid<<endl; 45 return 0; 46 }
D 题目链接
思路:从高为h处开始,雪球重量加此处的高度。到有石头处时,重量先增加此处高度,再减去石头的重量,若为负数则变为0。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 ll n,m; 5 int main() 6 { 7 ll i,j,k,x,y; 8 cin>>n>>m; 9 cin>>j>>k; 10 cin>>x>>y; 11 ll as=0; 12 for(i=m;i>=0;--i) 13 { 14 n+=i; 15 if(i==k)n-=j; 16 if(i==y)n-=x; 17 n=max(as,n); //n不可能为负数 18 } 19 cout<<n<<endl; 20 return 0; 21 }
E 题目链接
思路:当x和y的差值为0或1时,所包含的方形是最优的,所以x y逐渐增加判断是否大于等于n即可 //刚开始没读清题,以为要x y恰好表示n个方形qwq
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int qs=1e5+7; 5 const int inf=0x3f3f3f3f; 6 ll n,m; 7 int main() 8 { 9 cin>>n; 10 ll x=1,y=1; 11 while(x*y<n) 12 { 13 if(x>y) y++; 14 else x++; 15 } 16 ll ans=x+y; 17 cout<<ans; 18 return 0; 19 }
F 题目链接
思路:?可以删减或保留前一个字母。* 可以删减、保留或复制多次前一个字母。遍历字符串s,求出字母数量num, ? 数量num1, * 数量num2。
若num<k,则字母数量需要增加。若num2=0,是不可能的。若num2>0,则只需找到第一个*的位置,将它前一个字母复制k-num次。
若num<k,则字母数量需要减少。若k+num1+num2<num,是不可能的。否则每遇到'?'或'*'都将前一个字母删除,直到删除num-k次。
若num=k,字母数量不变。提取字母部分即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int qs=1e5+7; 5 const int inf=0x3f3f3f3f; 6 ll n,m; 7 int main() 8 { 9 int i,j,k; 10 string s,ss=""; 11 cin>>s; 12 cin>>k; 13 int l=s.size(); 14 int num=0,num1=0,num2=0; 15 for(i=0;i<l;++i) 16 { 17 if(s[i]=='?') num1++; 18 else if(s[i]=='*') num2++; 19 else num++; 20 } 21 // printf("s=%d\n num=%d\n",l,num); 22 int flag=1; 23 if(num<k) 24 { 25 int fg=1; 26 if(num2==0) flag=0; 27 else{ 28 for(i=0;i<l;++i) 29 { 30 if(s[i]>='a'&&s[i]<='z') ss+=s[i]; 31 else if(s[i]=='*'&&fg) //将前一个字母复制k-num次 32 { 33 for(j=1;j<=k-num;++j) 34 ss+=s[i-1]; 35 fg=0; 36 } 37 } 38 } 39 } 40 else if(num>k) 41 { 42 int sum=0; 43 if(num1+num2+k<num) flag=0; 44 else 45 { 46 for(i=0;i<l;++i) //模拟删除操作 47 { 48 if(s[i]=='*'||s[i]=='?') continue; 49 if(s[i+1]!='*'&&s[i+1]!='?') ss+=s[i]; //若一个字母后是字母,不能删除 50 else sum++; 51 if(sum==num-k) break; //删除次数够了,结束循环 52 } 53 for(j=i+1;j<l;++j) 54 if(s[j]!='*'&&s[j]!='?')ss+=s[j]; //将剩下的字母放到新的字符串里 55 } 56 } 57 else { 58 for(i=0;i<l;++i) 59 if(s[i]!='?'&&s[i]!='*') ss+=s[i]; 60 } 61 // printf("ss=%d\n",ss.size()); 62 if(flag) cout<<ss<<endl; 63 else cout<<"Impossible"; 64 return 0; 65 }