训练补题-个人1
# 个人排位赛1补题记录
# Removing Blocks(AtCoder AGC028-B)
两种做法:
考虑对于每个,会对答案产生多少贡献。对于,若取走时产生了的贡献,说明都未被取走,此时,设有中排列方法,而小于或大于的元素随意插入,共有中插法。由乘法原理,可知对产生了次贡献
也就是说,其他元素一共会对产生次贡献,再加上对自身产生的贡献次数。因此一共对答案产生了的贡献。
考虑将代价和变成代价均值乘方案数
若对有贡献,那么区间内必然先删除(与方法1原理相同)。那么产生贡献的期望次数为,总的答案为
# GTW likes czf(HDU 5598) 数位Dp
AC代码 (PS. 第一次见循环版数位Dp,感觉思路比递归版更清晰)
对一个大小为数集的每一个元素与亦或,得到的新的数集大小仍为,即不同的数与亦或后得到的数不同:假设,定有。
那么,该题的答案,为满足的数对的个数。
对式子稍作变换,得到,用数位Dp计数。
记为时,满足的对数。
最终答案为(容斥)
# Little Elephant and Boxes(CodeChef - LEBOXES) MeetInMiddle
求出前个物品买了个,用了个钻石时,使用的最少金币数。
接着把左半边的袋子所有可能性跑出来,按钻石数分组,组内按金币数排序。
右半边袋子同样处理。
枚举左半边钻石数,右半边钻石数,购买物品数,双指针扫描两个组即可。
理论AC
# Cross-stitch(URAL 1035) 题都没看
# AC代码
# AtCoder AGC028-B
#include <bits/stdc++.h>
#define ll long long
#define Android ios::sync_with_stdio(false), cin.tie(NULL)
using namespace std;
const int maxn = 1e5 + 100;
const ll mod = 1e9 + 7;
ll n, nfac = 1;
ll a[maxn], presum[maxn];
ll inv(ll base){
ll t = mod - 2, ret = 1;
for(; t; t>>=1){
if(t & 1) ret = ret * base % mod;
base = base * base % mod;
}
return ret;
}
void init(){
for(int i=2; i<=n; i++) nfac = nfac * i % mod;
for(int i=2; i<=n; i++){
presum[i] = (presum[i-1] + nfac * inv(i) % mod) % mod;
}
}
void solve(){
cin >> n;
init();
ll suma = 0, ans = 0;
for(int i=1; i<=n; i++) cin >> a[i], suma = (suma + a[i]) % mod;
for(int i=1; i<=n; i++){
ans = (ans + (presum[i] + presum[n - i + 1]) % mod * a[i]) % mod;
}
ans = (ans + suma * nfac % mod) % mod;
cout << ans << '\n';
}
signed main(){
Android;
solve();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# HDU 5598
# 1. 递归版数位dp
#include <bits/stdc++.h>
#define ll long long
#define Android ios::sync_with_stdio(false), cin.tie(NULL)
using namespace std;
const ll mod = 1e9 + 7;
int an[64], bn[64], xn[64];
ll dp[64][2][2];
ll calc(int bit, int lim_a, int lim_b){ // 数位dp巨多条件判断
if(bit == -1) return 1;
if(~dp[bit][lim_a][lim_b]) return dp[bit][lim_a][lim_b];
ll & ans = dp[bit][lim_a][lim_b] = 0;
if(lim_a && lim_b){
if(xn[bit]){
if(an[bit]) ans += calc(bit - 1, 1, bn[bit]==0);
if(bn[bit]) ans += calc(bit - 1, an[bit] == 0, 1);
}else{
if(an[bit] && bn[bit]) {
ans += calc(bit - 1, 0, 0);
ans += calc(bit - 1, 1, 1);
}else{
ans += calc(bit - 1, an[bit]==0, bn[bit]==0);
}
}
}else if(lim_a == 0 && lim_b == 0){
ans = 2 * calc(bit - 1, 0, 0);
}else{
ans += calc(bit - 1, lim_a, lim_b);
if(lim_a && an[bit]) ans += calc(bit - 1, 0, 0);
if(lim_b && bn[bit]) ans += calc(bit - 1, 0, 0);
}
return ans %= mod;
}
void set_val(ll a, ll b, ll x){
memset(dp, -1, sizeof dp);
for(int i=62; i>=0; i--){
an[i] = a >> i & 1;
bn[i] = b >> i & 1;
xn[i] = x >> i & 1;
}
}
void solve(){
ll l, r, g, t;
cin >> l >> r >> g >> t;
set_val(r, r, g ^ t);
ll ans = calc(63, 1, 1);
set_val(r, l - 1, g ^ t);
ll tmp = calc(63, 1, 1) * 2;
set_val(l - 1, l - 1, g ^ t);
ans = ((ans - tmp + mod) % mod + calc(63, 1, 1)) % mod;
cout << (2 * (r - l + 1) - ans + mod) % mod << '\n';
}
signed main(){
Android;
int t; cin >> t;
while(t--)
solve();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 2. 循环版
#include <bits/stdc++.h>
#define ll long long
#define Android ios::sync_with_stdio(false), cin.tie(NULL)
using namespace std;
const ll mod = 1e9 + 7;
int an[64], bn[64], xn[64];
ll dp[64][2][2];
void add(ll & val, ll delta){val = (val + delta) % mod;}
ll calc(ll a, ll b, ll x){
memset(dp, 0, sizeof dp);
for(int i=62; i>=0; i--){
an[i] = a >> i & 1;
bn[i] = b >> i & 1;
xn[i] = x >> i & 1;
}
dp[63][1][1] = 1;
for(int i=62; i>=0; i--){
if(an[i] ^ bn[i] == xn[i]) add(dp[i][1][1], dp[i+1][1][1]);
add(dp[i][1][0], dp[i+1][1][0]);
if(xn[i] == an[i] && bn[i]) add(dp[i][1][0], dp[i+1][1][1]);
add(dp[i][0][1], dp[i+1][0][1]);
if(xn[i] == bn[i] && an[i]) add(dp[i][0][1], dp[i+1][1][1]);
// dp[i][0][0]可以从[0][0], [0][1], [1][0], [1][1]转移过来
// 在if()里填入对应条件即可
add(dp[i][0][0], 2 * dp[i+1][0][0]);
if(an[i]) add(dp[i][0][0], dp[i+1][1][0]);
if(bn[i]) add(dp[i][0][0], dp[i+1][0][1]);
if(an[i] && bn[i] && xn[i]==0) add(dp[i][0][0], dp[i+1][1][1]);
}
return (dp[0][0][0] + dp[0][1][0] + dp[0][0][1] + dp[0][1][1]) % mod;
}
void solve(){
ll l, r, g, t, ans;
cin >> l >> r >> g >> t;
ans = (calc(r, r, g ^ t) + calc(l - 1, l - 1, g ^ t) - 2 * calc(r, l - 1, g ^ t) % mod + mod) % mod;
cout << (2 * (r - l + 1) - ans + mod) % mod << '\n';
}
signed main(){
Android;
int t; cin >> t;
while(t--) solve();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
上次更新: 2021/02/24, 03:37:30