2024牛客9

A.Image Scaling

题意:
给你一个有’.'或者’X’的矩阵。
把X矩阵等比例缩小到最小。

题解:
找到X矩阵的宽w和高h,计算gcd(w,h)。宽和高除gcd就行了。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N =2e5+6;
//int a[N];
string s[N];
void solve()
{
	int n,m;
	cin>>n>>m;
	
	for(int i=1;i<=n;i++)cin>>s[i];
	int a=0,b=0;
	
	for(int i=1;i<=n;i++){
		int t=0;
		s[i]=' '+s[i];
		for(int j=1;j<=m;j++){
			if(s[i][j]=='x')t++;
		}
		a=max(a,t);
	}
	for(int j=1;j<=m;j++){
		int t=0;
		for(int i=1;i<=n;i++){
			if(s[i][j]=='x')t++;
		}
		b=max(b,t);
	}
	
	int x=__gcd(a,b);
	for(int i=1;i<=b/x;i++){
		for(int j=1;j<=a/x;j++){
			cout<<'x';
		}
		cout<<'\n';
	}
	
}
signed main()
{
	int T=1;
//	cin>>T;
	while(T--){
		solve();
	}
    return 0;
}

K.Kill The Monsters

题意:
给定一个k。
有n个怪兽,第 i i i个怪兽有自己防御值 a i a_i ai,可以进行以下两种操作。
·所有怪兽防御值-1.
·选一个怪兽,让它的防御值变为 [ a i k ] [\frac{a_i}{k}] [kai].

问把所有怪兽的防御值都变为<=0的最小操作数。

题解:
首先特判k=1,操作二无意义,只使用操作一。

枚举使用操作二的次数。操作一的次数就是最大值的大小。

优先队列,每次取最大值用一次操作二,然后假设再全部用操作一。取所有答案的最小值。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N =2e5+6;
int a[N];
//string s[N];
void solve()
{
	int n,k;
	cin>>n>>k;
	priority_queue <int,vector<int>,less<int> > q;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		q.push(a[i]);
	}
	
	if(k==1){
		int ans=q.top();
		cout<<ans<<'\n';
		return  ;
	}
	int ans=1e18;
	int t=0;
	while(!q.empty()){
		int x=q.top();
		q.pop();
		ans=min(ans,t+x);
		x/=k;
		
		if(x>0)q.push(x);
		t++;
	}
	
	ans=min(ans,t);
	cout<<ans<<'\n';
}
signed main()
{
	int T=1;
//	cin>>T;
	while(T--){
		solve();
	}
    return 0;
}

I.Interesting Numbers

题意:
给定数字位数n, 1 < = n < = 60 1<=n<=60 1<=n<=60.n一定是偶数。
给定L,R。 1 0 n − 1 < = L < = R < 1 0 n 10^{n-1}<=L<=R<10^n 10n1<=L<=R<10n

问L~R中有多少个数字被为两半,可以得到两个平方数。这两半一定是相同长度。

题解:
一个数有 1 0 30 10^{30} 1030,我们用int128进行运算。
判断一个数有多少个平方数,可以用根号就行.
例如 30 = 5 \sqrt{30}=5 30 =5就代表有5个完全平方数。

我们把L,R分为4个数 l 1 , l 2 , r 1 , r 2 l1,l2,r1,r2 l1,l2,r1,r2分别代表L的前后部分,R的前后部分。
设top是与这些数相同位数的最大数,就是9999……
如果 l 1 l1 l1是完全平方数,就加入 t o p − l 2 − 1 \sqrt{top}-\sqrt{l2-1} top l21 ,代表 l 2 l2 l2~top的平方数个数。

如果 r 1 r1 r1是完全平方数,就加入 r 2 \sqrt{r2} r2

再找 l 1 l1 l1~ r 1 r1 r1有多少平方数,乘以 t o p \sqrt{top} top ,代表前部分是平方数,后部分是平方数的个数。

代码:

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;

typedef __int128 i128;
const __int128 MAX = LONG_LONG_MAX;

inline i128 read() {
    i128 x = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + (ch - '0');
        ch = getchar();
    }
    return x;
}

inline void print(i128 x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x > 9) {
        print(x / 10);
    }
    putchar(x % 10 + '0');
}
inline i128 Sqrtl(i128 x)
{
	i128 l=0,r=MAX,mid;
	while(l<r){
		mid=(l+r+1)/2;
		if(mid*mid>x){
			r=mid-1;
		}else l=mid;
	}
	return l;
}
void Solve() {
    ll n; cin >> n;
    string L, R;
    cin >> L >> R;
    ll half = n / 2;
    string l1_str = L.substr(0, half);
    string l2_str = L.substr(half);
    string r1_str = R.substr(0, half);
    string r2_str = R.substr(half);
    i128 l1 = 0, l2 = 0, r1 = 0, r2 = 0, top = 0;
    for (char c : l1_str) {
        l1 = l1 * 10 + (c - '0');
    }
    for (char c : l2_str) {
        l2 = l2 * 10 + (c - '0');
    }
    for (char c : r1_str) {
        r1 = r1 * 10 + (c - '0');
    }
    for (char c : r2_str) {
        r2 = r2 * 10 + (c - '0');
    }
    for(ll i = 1; i <= half; i ++ ) {
        top = top * 10 + 9;
    }
     
    i128 summ = Sqrtl(top) + 1;
    i128 sql1 = Sqrtl(l1), sql2 = Sqrtl(l2), sqr1 = Sqrtl(r1), sqr2 = Sqrtl(r2);
    i128 ans = 0;
    if(r1 == l1) {
        if(sqr1 * sqr1 == r1) {
            ans = sqr2 - sql2;
            if(sql2 * sql2 == l2) ans ++ ; 
        } 
        print(ans); return ;
    }
 
    if(sqr1 * sqr1 == r1) {
        ans += sqr2 + 1;
        sqr1 -- ;
    }
    if(sql1 * sql1 == l1) {
        ans += Sqrtl(top) - sql2;
        if(sql2 * sql2 == l2) ans ++ ;
    }
    ans += (sqr1 - sql1) * summ;
    print(ans);
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int T = 1;
    // cin >> T;
    while (T--) {
        Solve();
    }
//	i128 xx=read();
//	i128 an=Sqrtl(xx);
//	print(an);
    return 0;
}

H.Two Convex Polygons

题意:
给定两个凸多边形A,B。
A,B至少有一个共同点的情况下,B可以平移,翻转,反转,问B可以移动的覆盖范围形成的图形的边长是多少。

题解:
B和A至少一个共同点的最大图形,那我们找B图形的最长直径,围绕在A边一圈新构成的图形就是新图形。
求凸包最长直径,用旋转卡壳算法。先求凸包,再求直径,答案就是A的周长加上B直径为半径的圆的周长。
就是模板题

代码:

#include <bits/stdc++.h>

using namespace std;
const int N = 3e6 + 5;
const double eps = 1e-8;
const double PI=3.1415926535; 
int sgn(double x) {
    if (fabs(x) < eps) return 0;
    return (x > 0) ? 1 : -1;
}
int n;
struct Point {
    double x, y;
    Point(double x = 0, double y = 0) : x(x), y(y) {}
    void input() { scanf("%lf%lf", &x, &y); }
    bool operator<(const Point &b) const {
        if (sgn(y - b.y) == 0)
            return sgn(x - b.x) < 0;
        else
            return sgn(y - b.y) < 0;
    }
    Point operator-(const Point &b) const { return Point(x - b.x, y - b.y); }
    double operator^(const Point &b) const { return x * b.y - b.x * y; }
    bool operator==(const Point &b) const {
        return (sgn(x - b.x)) == 0 && (sgn(y - b.y) == 0);
    }
} a[N];
double dis(const Point &a, const Point &b) {
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
struct cmp {
    Point p;
    cmp() {}
    cmp(const Point &p0) { p = p0; }
    //以点p为极坐标原点进行极角排序:sort(,,p.cmp(mi));
    bool operator()(const Point &a, const Point &b) {
        int x = sgn((a - p) ^ (b - p));
        if (x == 0)
            return sgn(dis(a, p) - dis(b, p)) < 0;
        else
            return x > 0;
    }
};
//向量ab x 向量ac
double cross(Point a, Point b, Point c) { return (b - a) ^ (c - a); }
struct polygon {
    int n;
    Point p[N];
} convex;
//由a数组求凸包传给 P ———— 没想到求凸包这么简单,之前想得太难了,艹
void getconvex(Point *a, int n, polygon &convex) {
    Point mi = a[0];
    for (int i = 1; i < n; i++) mi = min(mi, a[i]);
    sort(a, a + n, cmp(mi));  //排序:求凸包的准备工作(这里不是极角排序)
    int top = 0;  // top模拟栈顶
    convex.p[top] = a[0];
    convex.p[++top] = a[1];
    for (int i = 2; i < n; i++) {
        while (top > 0 &&
               (sgn(cross(convex.p[top - 1], convex.p[top], a[i])) <= 0))
            top--;
        convex.p[++top] = a[i];
    }
    convex.n = top + 1;
}
// diameter:直径(zhijing)
double zhijing(Point *a, int n) {
    if (n == 2) return dis(a[0], a[1]);  //只有两个点
    double res = 0;
    int r =
        1;  //今天就栽在了这里。之前一直另的r=0,在Linr(a[0],a[1])的是时候就会出问题emmm
    a[n] = a[0];
    for (int i = 0; i < n; i++) {
        while (sgn(cross(a[i], a[i + 1], a[r + 1]) -
                   cross(a[i], a[i + 1], a[r])) > 0)
            r = (r + 1) % n;
        if (sgn(dis(a[i], a[r]) - res) > 0) res = dis(a[i], a[r]);
        if (sgn(dis(a[i + 1], a[r]) - res) > 0) res = dis(a[i + 1], a[r]);
        //这里为保险起见(一条线对应两个点的时候)。好像不要也是对的,为什么?这是一个大问题
        continue;
        while (sgn(cross(a[i], a[i + 1],
                         a[r + 1] - cross(a[i], a[i + 1], a[r]))) == 0) {
            r = (r + 1) % n;
            if (sgn(dis(a[i], a[r]) - res) > 0) res = dis(a[i], a[r]);
            if (sgn(dis(a[i + 1], a[r]) - res) > 0) res = dis(a[i + 1], a[r]);
        }
    }
    return res;
}
void solve()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].x>>a[i].y;
	}
	double ans=0;
	for(int i=2;i<=n;i++){
		ans+=dis(a[i],a[i-1]);
	}
	ans+=dis(a[1],a[n]);
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i].x>>a[i].y;
	}
	getconvex(a, n, convex);
	double cn= zhijing(convex.p, convex.n);
	ans+=2*PI*cn;
	cout << fixed << setprecision(13) << ans << "\n";
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

	int T;
	cin>>T;
	while(T--){
		solve();
		
	}
}```

  • 28
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值