出去交流了一阵子 回来打了个篮球杯 准备慢慢备战国赛和上半年CCPC
思路:直接模拟
// Code Start Here
int t;
cin >> t;
while(t--){
string a , b , c;
cin >> a >> b >> c;
cout << a[0] << b[0] << c[0] << endl;
}
思路:中间分别往左右蔓延
// Code Start Here
int t;
cin >> t;
while(t--){
int n , m , l , r;
cin >> n >> m >> l >> r;
int right = min(m , r);
int left = right - m;
cout << left << " " << right <<endl;
}
return 0;
思路:直接模拟,题目说明了G与P的关系,模拟一遍看谁没出现即可
// Code Start Here
int t;
cin >> t;
while(t--){
int n;
cin >> n;
vvi g(n+1,vi(n+1));
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n;j++){
cin >> g[i][j];
}
}
vi p(2*n);
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n;j++){
p[i+j-1]=g[i][j];
}
}
int ans = 0;
for(int i = 1;i<=2* n;i++)ans^= i;
for(int i : p)ans ^= i;
for(int i : p){
if(i == 0)cout << ans << " ";
else cout << i << " ";
}
cout << endl;
}
return 0;
这个题的名字很好玩
思路:观察到一个结论,我们注意到对于一个长度为x的连续的相同L或者R,可以允许的区间长度一定是 x ~ 2x,所以对应的,如果两端区间对应,那么长度的可能一定是有交集的,双指针扫一遍即可
// Code Start Here
int t;
cin >> t;
while(t--){
string a, b; cin >> a >> b;
vector<pair<char, int>> A, B;
int cnt = 1;
char buk = a[0];
for (int i = 0; i < a.size() - 1; ++i) {
if (a[i] != a[i + 1]) {
A.push_back({buk, cnt});
buk = a[i + 1];
cnt = 1;
} else {
cnt++;
}
}
A.push_back({buk, cnt});
cnt = 1;
buk = b[0];
for (int i = 0; i < b.size() - 1; ++i) {
if (b[i] != b[i + 1]) {
B.push_back({buk, cnt});
buk = b[i + 1];
cnt = 1;
} else {
cnt++;
}
}
B.push_back({buk, cnt});
bool f = true;
if (A.size() != B.size()) f = false;
for (int i = 0; i < A.size(); ++i) {
if (A[i].first != B[i].first || A[i].second > B[i].second || 2 * A[i].second < B[i].second) {
f = false;
}
}
if(f)cout << "YES" << endl;
else cout <<"NO" << endl;
}
return 0;
思路:观察数据范围 2^30,又是位运算,考虑按位贪心。
观察到题目要求求1 ~ n的k使得异或之和最大,根据位运算的性质,可以记录一下该位上1/0的个数,然后思考怎么使得和最大,答案显而易见肯定是能弄出来尽量多的1的更大,预处理后贪心即可
#define int long long了没有?
/ Code Start Here
int t;
cin >> t;
while(t--){
int n; cin >> n;
vector<int> a(n);
for(int i = 0;i<n;i++)cin >> a[i];
vvi v(n, vi(30));
vector<int> cnt0(30,0), cnt1(30,0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < 30; ++j) {
v[i][j] = (((a[i]) >> j) & 1);
if (v[i][j] == 1) {
cnt1[j]++;
} else {
cnt0[j]++;
}
}
}
int ans = 0;
for (int i = 0; i < n; ++i) {
int now = 0;
for (int j = 0; j < 30; ++j) {
if ((a[i] >> j) & 1) {
now += (cnt0[j]) * (1 << j);
} else {
now += (cnt1[j]) * (1 << j);
}
}
ans = max(ans, now);
}
cout << ans << endl;
}
return 0;
思路:我们发现可以直接输出1-k 但是样例1的2 2 2,即m,k为倍数关系,明显会导致上下相等,这个时候直接移位一位即可
// Code Start Here
int t;
cin >> t;
while(t--){
int n , m , k;
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int now = (i - 1) * m + j;
if (i % 2 == 1 && m % k == 0) {
now += 1;
}
int tmp;
if (now % k == 0) {
tmp = k;
} else {
tmp = now % k;
}
cout << tmp << ' ';
}
cout << endl;
}
}
return 0;
思路:观察题目,反转,前后移项,末尾添加,是deque。
思考元素乘以下标的和怎么快速改变
化简一下式子就有
操作1:
操作2:
操作3:
记得记录一下反转情况
// Code Start Here
int t;
cin >> t;
while(t--){
int q;
cin >> q;
deque<int> dq;
bool rev = false;
int sum = 0, now = 0;
int n = 0;
while(q--){
int s;
cin >> s;
if(s == 1){
int last;
if(!rev){
last = dq.back();
dq.pop_back();
dq.push_front(last);
} else {
last = dq.front();
dq.pop_front();
dq.push_back(last);
}
now += sum - n * last;
cout << now << endl;
} else if(s == 2){
now = (n + 1) * sum - now;
rev = !rev;
cout << now << endl;
} else {
int k;
cin >> k;
n++;
sum += k;
now += k * n;
if(!rev)
dq.push_back(k);
else
dq.push_front(k);
cout << now << endl;
}
}
}
return 0;
比较有思维量的一个题
题意:
你有一个整数数组 a,每个查询给出 k, l, r:初始值是 k遍历从 a[l] 到 a[r] 的元素,对 k 不断执行找到下一个位置 i,使得 a[i] 是 k 的约数在 i 到当前位置的范围,贡献为 区间长度 × 当前 k然后令 k /= a[i],重复这个过程最后,剩余未处理的区间长度 × 最终 k,加到结果中目标是输出所有查询的结果。
思路:
我们先预处理所有数的因数用于后续快速查找 k
的约数,然后建立数值到下标的映射,目的是为了查询某个值为x的数在数组里面的所有出现位置,方便通过二分找下一个满足条件的位置。然后不断寻找 k
的因数在 [l, r]
区间的最左位置即可
模拟+数论
// Code Start Here
const int N = 2e5+10;
vvi div(N);
for (int i = 2; i <= N; i++) {
for (int j = i; j <= N; j += i) {
div[j].push_back(i);
}
}
int t;
cin >> t;
while(t--){
int n, q;
cin >> n >> q;
vi a(n);
for(int i = 0;i<n;i++)cin >> a[i];
map<int, vi> mp;
for (int i = 0; i < n; i++) mp[a[i]].push_back(i);
while (q--) {
int k, l, r;
cin >> k >> l >> r;
l--;
r--;
int ans = 0;
int last = l;
while(true) {
if (k == 1) break;
int idx = -1;
for (auto i : div[k]) {
int near = lower_bound(all(mp[i]), l) - mp[i].begin();
if (near == mp[i].size()) continue;
int now = mp[i][near];
if (now > r) continue;
if (idx == -1 || now < idx) {
idx = now;
}
}
if (idx == -1) break;
ans += (idx - last) * k;
while (k % a[idx] == 0) k /= a[idx];
last = idx;
}
ans += (r - last + 1) * k;
cout << ans << endl;
}
}
return 0;