test20191024

闲扯

我太难了!!!

题面

题面

$T1$

Solution

我们考虑 $DP$ 。

设 $DP_{i,j}$ 表示 $(i-1,j-1)$ 都匹配成功,在 $(i,j)$ 处失配,其最短公共非子序列的长度, $dp_{0,0}$ 显然是 $0$ 。

考虑转移。

我们只在 $s_i=t_j$ 处转移。

假设最近下一处 $s_{i’}=t_{j’}$ 那么 $dp_{i’,j’}=\min(dp_{i’,j’},dp_{i,j}+1)$ 。

这是因为在此之间不存在相同的东西,所以我们将下一个定为 $s_{i’}$ ,一定可以保证 $(i’-1,j’-1)$ 不包含当前的串。

最后的答案就是 $dp_{n+1,m+1}$ 。

还需要解决是字典序。

我们将状态看做点,那么我们找的实际上就是一个图中 $(0,0)$ 到 $(n+1,m+1)$ 的最短路。

那么我们可以先将最短路树建出来(从 $(n+1,m+1)$ 开始倒着建),然后再贪心的走即可。

Code

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include<bits/stdc++.h>
#define del(a,i) memset(a,i,sizeof(a))
#define ll long long
#define inl inline
#define il inl void
#define it inl int
#define ill inl ll
#define re register
#define ri re int
#define rl re ll
#define mid ((l+r)>>1)
#define lowbit(x) (x&(-x))
#define INF 0x3f3f3f3f
using namespace std;
template<class T>il read(T &x){
int f=1;char k=getchar();x=0;
for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;
for(;k>='0'&&k<='9';k=getchar()) x=(x<<3)+(x<<1)+k-'0';
x*=f;
}
template<class T>il _print(T x){
if(x/10) _print(x/10);
putchar(x%10+'0');
}
template<class T>il print(T x){
if(x<0) putchar('-'),x=-x;
_print(x);
}
ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;}
it qpow(int x,int m,int mod){
int res=1,bas=x%mod;
while(m){
if(m&1) res=(1ll*res*bas)%mod;
bas=(1ll*bas*bas)%mod,m>>=1;
}
return res%mod;
}
const int MAXN = 4e3+5;
int n,m,nxt_s[MAXN][2],nxt_t[MAXN][2],dp[MAXN][MAXN];
char s[MAXN],t[MAXN],tr[MAXN][MAXN];
it min(int x,int y){return x<y?x:y;}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n),read(m);
scanf("%s%s",s+1,t+1);
nxt_s[n+1][0]=nxt_s[n+1][1]=n+1;
for(ri i=n;i;--i){
ri k=s[i]-'0';
nxt_s[i][k]=i;
nxt_s[i][k^1]=nxt_s[i+1][k^1];
}
nxt_t[m+1][0]=nxt_t[m+1][1]=m+1;
for(ri i=m;i;--i){
ri k=t[i]-'0';
nxt_t[i][k]=i;
nxt_t[i][k^1]=nxt_t[i+1][k^1];
}
del(dp,0x3f);
dp[0][0]=0;
for(ri i=0;i<=n+1;++i)
for(ri j=0;j<=m+1;++j)
for(ri k=0;k<2;++k){
if(dp[i][j]==INF) continue;
ri x=i<=n?nxt_s[i+1][k]:i;
ri y=j<=m?nxt_t[j+1][k]:j;
dp[x][y]=min(dp[x][y],dp[i][j]+1);
}
tr[n+1][m+1]=1;
for(ri i=n+1;i>=0;--i)
for(ri j=m+1;j>=0;--j)
for(ri k=0;k<2;++k){
ri x=i<=n?nxt_s[i+1][k]:i;
ri y=j<=m?nxt_t[j+1][k]:j;
if(dp[x][y]==dp[i][j]+1&&tr[x][y]) tr[i][j]=1;
}
for(ri i=0,j=0;i<=n||j<=m;)
for(ri k=0;k<2;++k){
ri x=i<=n?nxt_s[i+1][k]:i;
ri y=j<=m?nxt_t[j+1][k]:j;
if(dp[x][y]==dp[i][j]+1&&tr[x][y]){
putchar(k+'0');
i=x,j=y;
break;
}
}
return 0;
}

$T2$

Solution

首先明确一点:我们某一个数的选择次数一定是形如 $2^k-1$ 的。

因为对于一个 $popcnt=k$ 的点,我们将中间的 $0$ 去掉,消费一定更少。

然后我们可以贪心的来进行选取。

每次取出一个形如 $2^k*i$ 的数,表示 $i$ 这个数,从 $2^0,2^1,\cdots,2^{k-1}$ 都选过了,这一次增加 $2^k$ 个,而答案加 $1$ 。

我们可以用一个优先队列维护一下,每次取出一个 $2^ki$ 最小的数,答案加 $1$ ,然后加入 $2^{k+1}i$ 。

考虑优化这个过程。

我们可以发现,我们每次选的这个数是单调不减的,所以我们可以二分一个 $M$ ,表示所有代价不超过 $M$ 的形如 $2^k*i$ 的数我们全部选择。

然后判断是否超过 $n$ 。

我们找到一个最大的 $M$ 后,可能还剩了一些数。

我们再加上 $\lfloor\frac{rest}{M+1}\rfloor$ ,就是最后的答案。

这表示代价为 $M+1$ 的数我们没法选完,但是可能选择部分。

(不存在不足 $\lfloor\frac{rest}{M+1}\rfloor$ 个代价为 $M+1$ 的数的可能,因为如果不够,说明可以将 $M+1$ 买完,最后得到的就不是 $M$ 。)

Code

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
64
65
66
#include<bits/stdc++.h>
#define del(a,i) memset(a,i,sizeof(a))
#define ll long long
#define inl inline
#define il inl void
#define it inl int
#define ill inl ll
#define re register
#define ri re int
#define rl re ll
#define mid ((l+r)>>1)
#define lowbit(x) (x&(-x))
#define INF 0x3f3f3f3f
using namespace std;
template<class T>il read(T &x){
int f=1;char k=getchar();x=0;
for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;
for(;k>='0'&&k<='9';k=getchar()) x=(x<<3)+(x<<1)+k-'0';
x*=f;
}
template<class T>il _print(T x){
if(x/10) _print(x/10);
putchar(x%10+'0');
}
template<class T>il print(T x){
if(x<0) putchar('-'),x=-x;
_print(x);
}
ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;}
it qpow(int x,int m,int mod){
int res=1,bas=x%mod;
while(m){
if(m&1) res=(1ll*res*bas)%mod;
bas=(1ll*bas*bas)%mod,m>>=1;
}
return res%mod;
}
ll T,n,ans;
inl bool check(ll M){
ll sum=0;
ans=0;
int i=0;
for(ll j=1;M/j>=1;i++,j<<=1)
{
int r=M/j,l=M/(j<<1)+1;
ans+=(i+1)*(r-l+1);
sum+=((j<<1)-1)*(l+r)*(r-l+1)/2;
}
if(sum>n)return false;
ans+=(n-sum)/(M+1);
return true;
}
int main(){
read(T);
for(int i=1;i<=T;i++){
read(n);
ll l=1,r=1e9;
while(l<r){
if(check(mid+1)) l=mid+1;
else r=mid;
}
check(l);
printf("%lld\n",ans);
}
return 0;
}

$T3$

Solution

我们从小到大逐渐往中间加数。

对于一个数,我们考虑是左边还是放右边。

如果每一次交换,我们只在较小的那个数上计算,那么每一个数向左的代价就是满足 $ia_k$ 的 $a_i$ 的个数;向右的代价就是满足 $i>k,a_i>a_k$ 的 $a_i$ 的个数。

然后我们贪心的往两边放即可。

对于相同的数,我们可以发现,如果交叉放一定不会更优,所以我们一定是一段全部向左,剩下的全部向右。

用两个指针,从两边向中间贪心的放即可。

Code

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
64
65
66
67
68
69
#include<bits/stdc++.h>
#define del(a,i) memset(a,i,sizeof(a))
#define ll long long
#define inl inline
#define il inl void
#define it inl int
#define ill inl ll
#define re register
#define ri re int
#define rl re ll
#define mid ((l+r)>>1)
#define lowbit(x) (x&(-x))
#define INF 0x3f3f3f3f
using namespace std;
template<class T>il read(T &x){
int f=1;char k=getchar();x=0;
for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;
for(;k>='0'&&k<='9';k=getchar()) x=(x<<3)+(x<<1)+k-'0';
x*=f;
}
template<class T>il _print(T x){
if(x/10) _print(x/10);
putchar(x%10+'0');
}
template<class T>il print(T x){
if(x<0) putchar('-'),x=-x;
_print(x);
}
ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;}
it qpow(int x,int m,int mod){
int res=1,bas=x%mod;
while(m){
if(m&1) res=(1ll*res*bas)%mod;
bas=(1ll*bas*bas)%mod,m>>=1;
}
return res%mod;
}
const int MAXN = 3e5+5;
int n,val[MAXN],T[MAXN],l[MAXN],r[MAXN],id[MAXN];
ll ans;
il updata(int pos,int k){for(;pos<=n;pos+=lowbit(pos)) T[pos]+=k;}
it query(int pos){ri res=0;for(;pos;pos-=lowbit(pos)) res+=T[pos];return res;}
inl bool cmp(int x,int y){return val[x]==val[y]?x<y:val[x]<val[y];}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n);
for(ri i=1;i<=n;++i) read(val[i]),id[i]=i;
for(ri i=1;i<=n;++i){
l[i]=i-1-query(val[i]);
updata(val[i],1);
}
del(T,0);
for(ri i=n;i;--i){
r[i]=n-i-query(val[i]);
updata(val[i],1);
}
sort(id+1,id+1+n,cmp);
for(ri x=1,y=1;x<=n;x=y+1){
while(y<n&&val[id[y+1]]==val[id[x]]) ++y;
ri L=x,R=y;
while(L<=R){
if(l[id[L]]<=r[id[R]]) ans+=l[id[L]],++L;
else ans+=r[id[R]],--R;
}
}
print(ans);
return 0;
}

总结

这几天不在状态,要抓紧恢复!