问题 A: 颠倒是非
思路:直接输出1^x即可。
#include<iostream>
using namespace std;
int main(){
int x;
cin>>x;
cout<<(1^x)<<"\n";
}
问题 B: 乘法游戏
思路:我们可以发现答案一定是在 a×c 、a×d 、b×c 、b×d中出现。
#include<bits/stdc++.h>
using namespace std;
int main(){
long long a,b,c,d;
cin>>a>>b>>c>>d;
cout<<max(max(a*c,a*d),max(b*c,b*d))<<"\n";
}
问题 C: 合法序列数
思路:我们可以容斥一下,答案为总方案数 - 0或9没有出现的方案数。而0或9没有出现的方案数为0 没有出现的方案数 + 9 没有出现的方案数 - 0 和 9 都没有出现的方案数。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
ll powmod(ll x,ll y){
ll res=1;
for(ll i=0;i<y;i++){
res=res*x%mod;
}
return res;
}
int main(){
ll n;
cin>>n;
ll ans=powmod(10,n)-powmod(9,n)-powmod(9,n)+powmod(8,n);
ans%=mod;
ans=(ans+mod)%mod;
cout<<ans<<"\n";
}
问题 D: 合法序列数(2)
思路:
设 dp_i表示和为 i 的方案数。转移就是 dp_i = dp_i-1+dp_i-3。(和为i-1的序列的最后一个数加1或者在i-3的序列后加上一个3)
答案即为 dp_s。
#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
int main(){
int s,a[2010];
cin>>s;
a[0]=1,a[1]=a[2]=0;
for(int i=3;i<=s;i++){
a[i]=(a[i-1]+a[i-3])%mod;
}
cout<<a[s]<<endl;
}
问题 E: 曼哈顿距离
思路:首先我们要知道,平面上两点 (x1,y1)和 (x2,y2) 的曼哈顿距离等于 (x1−y1,x1+y1) 与 (x2−y2,x2+y2) 的切比雪夫距离。这个可以通过去绝对值来证明。然后即可O(N)去求对应点的最大切比雪夫距离是多少了。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
long long zmi=2e9,zma=-2e9,wmi=2e9,wma=-2e9;
cin>>n;
while(n--){
long long x,y;
cin>>x>>y;
zmi=min(zmi,x+y);
zma=max(zma,x+y);
wmi=min(wmi,x-y);
wma=max(wma,x-y);
}
cout<<max(zma-zmi,wma-wmi)<<"\n";
}
问题 F: 棋盘游戏
思路:
当我们放一个白子的时候,会改变多少黑子的颜色?
对于第一种操作,这是由该列最上面的白子决定的;对于第二种操作,这是由该行最左边的白子决定的。
而每种操作的影响是什么呢?第一种操作会影响 1…x 行( x 是操作的列最上面的白子所在的行),而第二种操作会影响 1…x列(x是操作的行最左边的白子所在的列)。
很自然地想到用线段树来处理。一个储存每行最上面的白子,另一个储存每列最左边的白子。对于非叶结点,我们存储区间的最大值。因为我们每次操作相当于一个切割,把所有大于XX的数都变为XX,因此,存储区间最大值,可以让我们很方便地判断当前的切割是否产生了影响。
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
#define MAXN 200005
#define lson (idx << 1)
#define rson (idx << 1 | 1)
using namespace std;
typedef long long ll;
struct Node {
int l, r, hi, lazy = 0;
};
struct SegTree {
Node s[MAXN << 2];
void calc(int idx) { s[idx].hi = max(s[lson].hi, s[rson].hi); }
void pushdown(int idx) {
if (s[idx].lazy) {
for (int i = lson; i <= rson; ++i) {
if (s[i].hi > s[idx].lazy) {
s[i].hi = s[idx].lazy;
s[i].lazy = s[idx].lazy;
}
}
}
s[idx].lazy = 0;
}
void build(int idx, int l, int r, vector<int> &a) {
s[idx].l = l, s[idx].r = r;
if (l == r) {
s[idx].hi = a[l];
return;
}
int mid = (l + r) >> 1;
build(lson, l, mid, a);
build(rson, mid + 1, r, a);
calc(idx);
}
void update(int idx, int l, int r, int x) {
if (s[idx].hi <= x)
return;
if (s[idx].l >= l && s[idx].r <= r) {
s[idx].hi = x;
s[idx].lazy = x;
return;
}
pushdown(idx);
int mid = (s[idx].l + s[idx].r) >> 1;
if (l <= mid)
update(lson, l, r, x);
if (mid + 1 <= r)
update(rson, l, r, x);
calc(idx);
}
int query(int idx, int l, int r) {
if (s[idx].l >= l && s[idx].r <= r)
return s[idx].hi;
pushdown(idx);
int ans = 0;
int mid = (s[idx].l + s[idx].r) >> 1;
if (l <= mid)
ans = max(ans, query(lson, l, r));
if (mid + 1 <= r)
ans = max(ans, query(rson, l, r));
return ans;
}
};
int main() {
int n, q;
cin >> n >> q;
vector<int> col(n + 1, n), row(n + 1, n);
col[n] = 1, row[n] = 1;
SegTree C, R;
C.build(1, 1, n, col);
R.build(1, 1, n, row);
ll ans = (ll)(n - 2) * (n - 2);
for (int i = 0; i < q; ++i) {
int t, x;
cin >> t >> x;
if (t == 1) {
int hi = C.query(1, x, x);
ans -= hi - 2;
R.update(1, 1, hi, x);
C.update(1, x, x, 1);
} else {
int hi = R.query(1, x, x);
ans -= hi - 2;
C.update(1, 1, hi, x);
R.update(1, x, x, 1);
}
}
cout << ans;
}