7-5 田忌赛马·Hard
先同easy版对比一下:
解决方法:对两组进行排序,如果a[n-i-1]>b[k-i-1],则k++;
解题思路:——二分
根据题目可知,我们寻找的是从某一天开始a中的🐎至少获胜k场,那么在这一天之前获胜场数一定是小于k,根据这种性质(类似于单调性)我们可以判断我们设定的第M天是在答案天数的左侧还是右侧,从而可以利用二分解决这个问题。
蒟蒻的代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e8;
int t,k,n;
struct pp{
int a;
int aa;
}p[11000];
int b[11000];
int check(int mid){
vector<int>v;
for(int i=0;i<n;i++) v.push_back(p[i].a+p[i].aa*mid);
sort(v.begin(),v.end());
int kk=0;
int num=0;
for(int i=0;i<k;i++){
if(v[n-i-1]>b[k-i-1])
kk++;
}
if(kk>=k) return 1;
return 0;
}
signed main(){
ios::sync_with_stdio(false);
cin>>t;
while(t--){
cin>>n>>k;
for(int i=0;i<n;i++) cin>>p[i].a>>p[i].aa;
for(int i=0;i<n;i++) cin>>b[i];
int l = 0, r = N;
sort(b,b+n);
if(!check(r)) cout<<-1<<endl;
else{
while(l<r){
int mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid+1;
}
cout<<l<<endl;
}
}
return 0;
}
注意考虑不能改变a中🐎的初始速度,照常搬运y总二分模板就可以ac了(y总牛批)
侯学长的代码:(我的stl还是不行啊/(ㄒoㄒ)/~~)
#include <bits/stdc++.h>
#define int long long
#define a first
#define b second
using namespace std;
const int N = 10010;
int t, n, k;
pair<int, int>my[N];
int op[N];
bool check(int mid) {
int win = 0, idx = 0;
vector<int>cur;
for (int i = 0;i < n; i++) cur.push_back(my[i].a + my[i].b * mid);
sort(cur.begin(), cur.end(), greater<int>());
for (int i = 0;i < n; i++) {
if (cur[idx] > op[i]) idx++, win++;
}
return win >= k;
}
signed main() {
scanf("%lld", &t);
while (t--) {
scanf("%lld %lld", &n, &k);
for (int i = 0;i < n; i++) scanf("%lld %lld", &my[i].a, &my[i].b);
for (int i = 0;i < n; i++) scanf("%lld", &op[i]);
int l = -1, r = 0x3f3f3f3f;
sort(op, op + n, greater<int>());
if (!check(r)) puts("-1");
else {
while (r - l != 1) {
int mid = (l + r) / 2;
if(check(mid)) r = mid;
else l = mid;
}
printf("%lld\n", r);
}
}
return 0;
}
7-7 放置方案数
dp题/(ㄒoㄒ)/~~
- 最多可以有连续两个盒子放相同颜色的球,所以只需要考虑连续的三个盒子即可
- 用dp[i] [0]表示第 i 个盒子放和第 i−1 个盒子球颜色不同的球的方案数
- 用dp[i] [1]表示第 i 个盒子放和第 i−1 个盒子球颜色相同的球的方案数
- dp[i] [0] = (dp[i - 1] [0] + dp[i - 1] [1]) * (k - 1) % Mod;
- dp[i] [1] = dp[i - 1] [0];
#include <bits/stdc++.h>
#define int long long
using namespace std;
int T, n, k;
int dp[100005][2];
const int Mod = 1e9 + 7;
signed main() {
scanf("%lld", &T);
while (T--) {
scanf("%lld%lld", &n, &k);
dp[1][0] = k;
dp[1][1] = 0;
for (int i = 2; i <= n; i++) {
dp[i][0] = (dp[i - 1][0] + dp[i - 1][1]) * (k - 1) % Mod;
dp[i][1] = dp[i - 1][0];
}
printf("%lld\n", (dp[n][0] + dp[n][1]) % Mod);
}
return 0;
}
7-6 搭帐篷
二维前缀和+二分,题解慢慢写吧。。。学长的代码确实妙啊
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int L,W;
int a[N][N],s[N][N];
bool check(int mid){
mid--;
for(int i=1;i<=L-mid;i++){
for(int j=1;j<=W-mid;j++){
int x1=i,x2=i+mid,y1=j,y2=j+mid;
if(s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]==0)
return true;
}
}
return false;
}
int main() {
while(cin>>L>>W){
if(!L&&!W) break;
memset(a,0,sizeof(a));
for(int i=1;i<=L;i++){
for(int j=1;j<=W;j++){
cin>>a[i][j];
if(a[i][j]==1)
a[i][j]=0;
}
}
for(int i=1;i<=L;i++){
for(int j=1;j<=W;j++){
s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1];
}
}
/* if(min(L,W)==1){
int flag=0;
for(int i=1;i<=L;i++){
for(int j=1;j<=W;j++){
if(a[i][j]==0){
flag=1;
}
}
}
if(!flag)
cout<<0<<endl;
else
cout<<1<<endl;
}*/
// else{
int l=-1,r=min(L,W),ans=0;
while(l<r){
int mid= l+r+1 >>1;
if(check(mid)){
l=mid;
ans=mid;
}
else r=mid-1;
}
cout<<ans*ans<<endl;
// }
}
return 0;
}
7-4 螺旋矩阵
模拟,这个题写不出应该回炉重造C语言
这个题最难过的点就是输出——如何正确输出模拟后的螺旋:
- 因为无法判断字符最后的落点,所以使用从里往外旋的方法比较简单
- 必须按字符串一行一行输出(暂时没有更好的方法),不能一个一个字符输出,因为最后一个字符的落点不能判断,所以无法判断每一行是否有正好ey-by+1个字符,而直接输出一行可以避免这个问题
- 注意每个矩阵之间有一个空行
#include<bits/stdc++.h>
using namespace std;
char c[1100][1100];
string s;
int t;
int main(){
cin>>t;
getchar();
while(t--){
cin>>s;
memset(c,0,sizeof(c));
int x=500,y=500,v=4;
for(int i=0;i<s.size();i++){
c[x][y]=s[i];
if(v==1){
if(c[x-1][y]==0) v=3,x--;
else y++;
}else if(v==2){
if(c[x+1][y]==0) v=4,x++;
else y--;
}else if(v==3){
if(c[x][y-1]==0) v=2,y--;
else x--;
}else if(v==4){
if(c[x][y+1]==0) v=1,y++;
else x++;
}
}
int bx=500,by=500,ex=500,ey=500;
for(int i=0;i<1000;i++){
for(int j=0;j<1000;j++){
if(c[i][j]!=0){
if(i<bx) bx=i;
if(i>ex) ex=i;
if(j>ey) ey=j;
if(j<by) by=j;
}
}
}
for(int i=bx;i<=ex;i++){
for(int j=by;j<ey;j++){
if(c[i][j]=='\0') c[i][j]=' ';
else break;
}
}
for(int i=bx;i<=ex;i++){
cout<<c[i]+by<<endl;
}
cout<<endl;
}
return 0;
}
左上右下循环,每次判断下一种情况下的位置是否为0,若为0,转为下一种情况,否则继续该情况