AtCoder Beginner Contest 189 解题报告

题目链接:https://atcoder.jp/contests/abc189/tasks

A - Slot

题目大意

输入一个串,只包含三个字符,如果都相同,输出“Won”, 否则输出“Lost”

思路

水题。

ac代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
    string a; cin >> a;
    if(a[0] == a[1] && a[0] == a[2]) puts("Won");
    else puts("Lost");
    return 0;
}

B - Alcoholic

题目大意

喝酒。有n瓶酒,每瓶酒ai毫升,酒精浓度时bi,Takahashi的酒量是m,然后他要顺序喝酒,问你他喝到第几瓶的时候会醉,如果所有酒都喝完还没醉(他的肚子很大,能容下所有!),则输出-1。

思路

模拟。计算没瓶酒的酒精含量ai*bi,然后顺序喝直到超过酒量m*100。

ac代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5 + 5;
int a[maxn];
int main(){
    int n, m;
    cin >> n >> m;
    m *= 100;
    for(int i = 1; i <= n; i ++){
        int x, y;
        cin >> x >> y;
        a[i] = x * y;
    }
    int ans = -1, id = 1;
    while(id <= n){
        m -= a[id];
        ans = id ++;
        if(m < 0) break;
    }
    if(m >= 0) ans = -1;
    cout << ans << endl;
    return 0;
}

C - Mandarin Orange

题目大意

n个数,操作(l, r, x)表示区间[l, r]里面的数,满足每个数都大于等于x,代表的值s = x * (r - l + 1), 求满足条件的s的最大值

思路

暴力。针对每个位置的数分别左右扩散,直到边界值小于该值,然后更新最大值即可。

ac代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e4 + 5;
int a[maxn];
int main(){
    int n; cin >> n;
    for(int i = 1; i <= n; i ++){
        cin >> a[i];
    }
    int ans = 0;
    for(int i = 1; i <= n; i ++){
        int id = i + 1, l = i, r = i; //l,r分别代表扩展左右边界
        while(id <= n && a[i] <= a[id]){
            r = id ++;
        }
        id = i - 1;
        while(id >= 1 && a[i] <= a[id]) {
            l = id --;
        }
        ans = max(ans, a[i] * (r - l + 1)); //(l, r, x) 这里的a[i]就作为x, 区间长度是r - l + 1,所以代表的值就是a[i] * (r - l + 1)
    }
    cout << ans << endl;
    return 0;
}

D - Logical Expression

题目大意

给你n个字符串,要么是"AND",要么是"OR",分别代表位运算中的与运算和或运算,然后让你构造长度为n+1的仅包含"False"和"True"的序列,使得带入n个字符串组成的运算式最终结果是True,问你这样的序列有几个。

比如样例的2个串"AND","OR",那么构造的序列可以是{True, False, True},因为 True & False | True = True。这样的序列有5个,则输出5

思路

有点像dp的递推式,假设从第1个位置到第i-1个位置做运算之后结果是True的数量为a1初始化是1,结果是False的数量为a2初始化是1。

如果第i个位置的操作是AND,那么运算结果是True的话,那么只能1&1,也就是说到第i个位置运算结果是True的数量是a1;否则运算结果是False的话,那么可以是1&0,0&1,0&0,也就是说到第i个位置运算结果是False的数量是a1+a2+a2。

同理,如果第i个位置的操作是OR,那么运算结果是True的话,那么可以是1|1, 1|0, 0|1,也就是说到第i个位置运算结果是True的数量是a1+a1+a2;否则运算结果是False的话,那么只能是0|0,也就是说到第i个位置运算结果是False的数量是a2。

最后结果就是递推到最后的a1。

ac代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e4 + 5;
string a[66];
int main(){
    ll ans = 0;
    int n; cin >> n;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    ll a1 = 1, a2 = 1, t1, t2;
    for(int i = 1; i <= n; i ++){
        if(a[i] == "OR"){
            t1 = a1 * 2 + a2;
            t2 = a2;
        }else{
            t1 = a1;
            t2 = a1 + a2 * 2;
        }
        a1 = t1, a2 = t2;
    }
    cout << a1 << endl;
    return 0;
}

E - Rotate and Flip

题目大意

n个点,m次操作,q次询问。接下来是n个点的横纵坐标,m次操作指令op,如果op=1,那就让每个点绕原点顺时针旋转90度;如果op=2,那就让每个点绕原点逆时针旋转90度;如果op=3,再输入p,那就让每个点变成关于直线x=p的对称点;如果op=4,再输入p,那就让每个点变成关于直线y=p的对称点;然后q次询问,每次询问a,b,问b次操作之后点a的坐标。 n,m,q<=2e5, xi,yi<=1e9;

思路

范围这么大,首先肯定离线处理。然后自从学过图形学之后可以发现,绕着原点旋转其实就是绕着三维的z轴旋转,对称点,其实也是旋转,那么都可以看作是矩阵相乘之后的结果。矩阵相乘满足结合律,所以可以预处理出前几个运算矩阵的前缀乘,询问的时候直接初始坐标左乘变换矩阵就是最后坐标了。那么怎么构建这个变换矩阵呢?可以先把坐标前和坐标后的矩阵写出来反过来求变换矩阵。首先毕竟是旋转,考虑到z轴了, 那么肯定是三个变量,所以变换矩阵是3*3的,坐标就要加一维,一般设置为1,可以继承。

就拿顺时针旋转举例,就默认(x,y)是在第一象限的,旋转前是\begin{bmatrix} x\\ y\\ 1 \end{bmatrix},旋转后是\begin{bmatrix} y\\ -x\\ 1 \end{bmatrix},发现x和y互换位置,然后x加了负号,所以可以推算出变换矩阵是\begin{bmatrix} 0 & 1 & 0\\ -1& 0 & 0\\ 0& 0 &1 \end{bmatrix},那么同理逆时针旋转的变换矩阵就是\begin{bmatrix} 0 & -1 & 0\\ 1& 0 & 0\\ 0& 0 &1 \end{bmatrix};

拿关于x=p对称举例,对称前是\begin{bmatrix} x\\ y\\ 1 \end{bmatrix},对称后是\begin{bmatrix} 2*p-x\\ y\\ 1 \end{bmatrix},发现y,1都没变,唯一变的是x,变负数,加了2*p,所以可以推算出变换矩阵是\begin{bmatrix} -1 & 0 & 2*p\\ 0& 1 & 0\\ 0& 0 &1 \end{bmatrix},那么同理逆时针旋转的变换矩阵就是\begin{bmatrix} -1 & 0 & 0\\ 0& 1 & 2*p\\ 0& 0 &1 \end{bmatrix};

注意,变换变换,都是矩阵左乘!就是opi*op(i-1)*...*op1*a;还有数据开longlong

ac代码

#include<bits/stdc++.h>
using namespace std;
mt19937_64 rng(time(0));
#define io cin.tie(0);ios::sync_with_stdio(false);
#define ok(x, y) x >= 1 && x <= n && y >= 1 && y <= m
#define debug(x) cout<<#x<<"="<<x<<endl
#define lowbit(x) x&(-x)
#define pii pair<int,int>
#define mk make_pair
#define ll long long
#define ull unsigned long long
#define rs p<<1|1
#define ls p<<1
const int maxn = 2e5 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 1e18;
inline ll read(){
    ll p=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){p=(p<<1)+(p<<3)+(c^48),c=getchar();}
    return f*p;
}
void print(__int128 x){
    if(x<0) {putchar('-'); x=-x;}
    if (x>9) print(x/10);
    putchar('0'+x%10);
}

struct mat{
    ll a[5][5];
    mat(){
        memset(a, 0, sizeof(a));
    }
    mat operator * (const mat b)const{ //重载乘
        mat tmp;
        for(int i = 1; i <= 3; i ++){
            for(int j = 1; j <= 3; j ++){
                tmp.a[i][j] = 0;
                for(int k = 1; k <= 3; k ++){
                    tmp.a[i][j] += a[i][k] * b.a[k][j]; //矩阵乘法不满足交换律,所以不能写反
                }
            }
        }
        return tmp;  
    }
}op[5], ans[maxn];

void init(){ //初始化变换矩阵
    op[1].a[1][2] = op[1].a[3][3] = 1; op[1].a[2][1] = -1;
    op[2].a[2][1] = op[2].a[3][3] = 1; op[2].a[1][2] = -1;
    op[3].a[2][2] = op[3].a[3][3] = 1; op[3].a[1][1] = -1;
    op[4].a[1][1] = op[4].a[3][3] = 1; op[4].a[2][2] = -1;
}

struct node{
    int x, y;
}a[maxn];
ll x[maxn], y[maxn];
ll n, m, q;
void pre(){ //预处理前缀乘
    ans[0].a[1][1] = ans[0].a[2][2] = ans[0].a[3][3] = 1; //单位矩阵
    for(int i = 1; i <= m; i ++){
        ans[i] = op[a[i].x];
        if(a[i].x == 3) ans[i].a[1][3] = 2 * a[i].y;
        else if(a[i].x == 4) ans[i].a[2][3] = 2 * a[i].y;
        ans[i] = ans[i] * ans[i - 1];
    }
}
void solve(){
    init();
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> x[i] >> y[i];
    cin >> m;
    for(int i = 1; i <= m; i ++){
        cin >> a[i].x;
        if(a[i].x >= 3) cin >> a[i].y;
    }
    pre();
    cin >> q;
    while(q --){
        ll xx, yy;
        cin >> yy >> xx;
        mat tmp = ans[yy];
        mat res; res.a[1][1] = x[xx], res.a[2][1] = y[xx], res.a[3][1] = 1; //[x, y, 1]
        res = tmp * res; //左乘!
        cout << res.a[1][1] << " " << res.a[2][1] << endl;
    }
}
int main(){
    // freopen("1.in", "r", stdin);
    // freopen("std.out", "w", stdout);
    // cout << fixed << setprecision(6)
    io;
    solve();
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值