题目链接: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)是在第一象限的,旋转前是,旋转后是
,发现x和y互换位置,然后x加了负号,所以可以推算出变换矩阵是
,那么同理逆时针旋转的变换矩阵就是
;
拿关于x=p对称举例,对称前是,对称后是
,发现y,1都没变,唯一变的是x,变负数,加了2*p,所以可以推算出变换矩阵是
,那么同理逆时针旋转的变换矩阵就是
;
注意,变换变换,都是矩阵左乘!就是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;
}