文章目录
刷题之Codeforces Round #757 (Div. 2)
[1614A]. Divan and a Store
- 思路:存入所有可选的,从小到大选择
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define db double
#define VI vector<int>
#define PII pair<int, int>
const db Pi = 3.141592653589793;
const int INF = 0x7fffffff;
const int N = 1e5 + 5;
const db eps = 1e-10;
int cas, n, l, r, k, a[N], ans, cnt;
int main(){
cin >> cas;
while(cas--){
cin >> n >> l >> r >> k;
cnt = 0;
rep(i, 1, n){
int x; cin >> x;
if(l <= x && x <= r) a[++cnt] = x;
}
sort(a + 1, a + 1 + cnt);
ans = 0;
for(int i = 1; i <= cnt; i++){
if(k < a[i]) break;
k -= a[i];
ans++;
}
cout << ans << endl;
}
}
[1614B]. Divan and a New Project
- 思路:不妨设 x 0 x_0 x0 在原点处。由于所有位置需要为整数,且要求距离最短,即为 ± 1 , ± 2 , . . . \pm1,\pm2,... ±1,±2,...。贪心选择,要去次数最多的放到最近,于是排序按照访问次数从大到小依次赋位置 + 1 , − 1 , + 2 , − 2 , . . . +1,-1,+2,-2,... +1,−1,+2,−2,... 即可。
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define db double
#define VI vector<int>
#define PII pair<int, int>
const db Pi = 3.141592653589793;
const int INF = 0x7fffffff;
const int N = 2e5 + 5;
const db eps = 1e-10;
int cas, n, m;
ll ans, a[N];
struct AC{
ll w, num;
}node[N];
bool cmp(AC a, AC b){
return a.w > b.w;
}
int main(){
cin >> cas;
while(cas--){
cin >> n;
rep(i, 1, n){
cin >> node[i].w;
node[i].num = i;
}
sort(node + 1, node + 1 + n, cmp);
ans = 0, a[0] = 0;
rep(i, 1, n){
int nowaddr = ((i % 2 == 0) ? (-1 * (i / 2)): (i / 2 + 1));
a[node[i].num] = nowaddr;
ans += node[i].w * abs(nowaddr); //这里需要long long
}
cout << ans * 2 << endl;
rep(i, 0, n) printf("%d ", a[i]);
cout << endl;
}
}
[1614C]. Divan and bitwise operations
-
思路:拆位依次运算。
-
首先,若序列 { a } \{a\} {a} 中至少有一个 a i a_i ai 在某位为 1 1 1,则序列中所有数 a i a_i ai 在这一位组成的 01 01 01 序列的所有非空子集的异或和为 2 n − 1 2^{n-1} 2n−1。
证明:设这一位有
a
个 1 1 1 和b
个 0 0 0,必有有 a + b = n a+b=n a+b=n。由于对于一个所选子集,只有恰存在奇数个 1 1 1 时,异或和才为 1 1 1。所以对于 n n n 个元素的 2 n 2^n 2n 个子集,选择奇数个 1 1 1 的集合应为 2 n − 1 2^{n-1} 2n−1 个。
在 a 个 1 中 选 择 : C a 1 + C a 3 + C a 5 + . . . = 2 a − 1 在 b 个 0 中 选 择 : 为 2 b 总 计 有 : 2 a − 1 ∗ 2 b = 2 n − 1 \begin{aligned}在a个1中选择&:C_a^1+C_a^3+C_a^5+...=2^{a-1}\\ 在b个0中选择&:为2^b\\ 总计有&: 2^{a-1}*2^b=2^{n-1}\\ \end{aligned} 在a个1中选择在b个0中选择总计有:Ca1+Ca3+Ca5+...=2a−1:为2b:2a−1∗2b=2n−1 -
只需要检查原序列 { a } \{a\} {a} 中每一位是否有 1 1 1。若有 1 1 1 则第 t t t 位的贡献为 2 n − 1 ∗ 2 t 2^{n-1}*2^t 2n−1∗2t。因为给的是序列区间的或运算结果,则若有 a i a_i ai 在此位为 1 1 1,其所在区间或运算在此为必为 1 1 1。只有在全部区间在此位都为 0 0 0 时才能证明 { a } \{a\} {a} 序列中每一个元素在此位均为 0 0 0。
-
最后计算贡献之和即可。
-
-
最坏复杂度: O ( 30 ∗ m log n ) O(30*m\log n) O(30∗mlogn)
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define db double
#define VI vector<int>
#define PII pair<int, int>
const db Pi = 3.141592653589793;
const int INF = 0x7fffffff;
const int N = 2e5 + 5;
const ll mod = 1e9 + 7;
const db eps = 1e-10;
int cas, n, m, seg[N];
ll ans;
ll power(ll a, ll b, ll mod){
ll ans = 1;
if(mod == 1) ans = 0;
while(b > 0){
if(b % 2 == 1){
ans *= a;
ans %= mod;
}
a *= a;
a %= mod;
b >>= 1;
}
return ans;
}
int main(){
cin >> cas;
while(cas--){
cin >> n >> m;
rep(i, 1, m){
int x, y;
cin >> x >> y >> seg[i];
}
ans = 0;
rep(k, 0, 30){
int t = (1 << k), ok = 0;
rep(i, 1, m){
if((seg[i] & t) > 0){ //只要这一位有一个数字为 1 ,这一位所有子集异或和为 2^(onenum + zeronum - 1)
ok = 1;
break;
}
}
if(ok) (ans += (power(2ll, n - 1, mod) * t) % mod) %= mod;
}
cout << ans << endl;
}
}