CF1288题解
CF1288
Educational Codeforces Round 80 (Rated for Div. 2)
A略
CF1288B
CF1288B题意
-
给定 \(A,B\),问有多少个二元组 \((a,b)\) 满足 \(1\le a \le A,1\le b\le B\) 且 \(a\cdot b+a+b=\operatorname{conc}(a,b)\)。其中 \(\operatorname{conc}(a,b)\) 表示将 \(a,b\) 拼接在一起,比如 \(\operatorname{conc}(12,23)=1223,\operatorname{conc}(100,11)=10011\),\(a,b\) 不能含有前导 \(0\)。
-
本题有多组数据。令数据组数为 \(T\),\(T\le 100\),\(A\le 10^9\),\(B\le 10^9\)。
CF1288B题解
不妨设 \(b\) 的位数是 \(count(b)\)。
那么有
发现这个式子与 \(a\) 无关,成立当且仅当 \(b=10^k-1\)。
不难发现这样的 \(b\) 形如 \(9,99,999,\dots,999\dots999\)(设成立的总数是 \(f(b)\))。
而只要 \(b\) 满足了,\(a\) 是什么都无所谓,答案就是 \(a\times f(b)\)。
没了。
CF1288B代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
signed main(){
int T = read();
while(T--){
int a = read(), b = read();
int cnt = 0,tmp = 1;
while(tmp - 1 <= b){tmp *= 10;cnt++;}
if(cnt)cnt--;
printf("%lld\n",a * cnt);
}
return 0;
}
CF1288C
CF1288C题意
输入两整数 \(n\)、\(m\),求有多少对正整数序列 \(a_i\)、\(b_i\) 满足:
- \(a_i\)、\(b_i\) 的长度为 \(m\);
- \(a_i\)、\(b_i\) 中所有元素的值小于等于 \(n\);
- 对于所有 \(1\le i\le m\),\(a_i\le b_i\);
- 序列 \(a\) 单调不降,序列 \(b\) 单调不升。
答案对 \(10^9+7\) 取模。
CF1288C题解
首先将 \(b\) 序列左右对称一下,然后接到 \(a_m\) 后面,不难发现,原题转化为求值域是 \([1,n]\),长度是 \(2\times m\) 的序列的数量。
简单DP即可。
CF1288C代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 1e3 + 10;
const ll mod = 1e9 + 7;
int n, m;
ll f[42][maxn];
signed main(){
n = read(); m = read();
for(int i = 1;i <= n;i++)f[1][i] = 1;
for(int i = 2;i <= m * 2;i++){
ll sum = 0;
for(int j = 1;j <= n;j++){
// printf("%d %d\n",i,j);
sum += f[i - 1][j];
if(sum > mod)sum -= mod;
f[i][j] = sum;
}
}
ll sum = 0;
for(int i = 1;i <= n;i++){
sum += f[m * 2][i];if(sum > mod)sum -= mod;
// printf("%lld\n",f[m * 2][i]);
}
printf("%lld\n",sum);
return 0;
}
CF1288D
CF1288D题意
给出一个 \(n\) 行 \(m\) 列的数字矩阵 \(a\),找出两行 \(x, y\),令 \(b_j = \max(a_{x, j}, a_{y, j})\),试使得 \(\min\limits_{1 \le j \le m}b_j\) 最大,输出选择的 \(x, y\),可以相同。
CF1288D题解
二分最大的 \(\min\limits_{1 \le j \le m}b_j=x\),然后考虑怎么验证答案 \(x\) 是否合法。
先将矩阵中所有 \(a_{i,j}\ge x\) 的标记为 \(1\),否则标记为 \(0\)。
如果将每一行(别忘了 \(m\le8\))都压缩成二进制,那么问题就转变成找到两行,使得 \(or\) 值是 \(2^m-1\)。
这东西想怎么做怎么做,DP,dfs,随意。
CF1288D代码
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 3e5 + 10;
int a[maxn][8];
int n, m;int f[1 << 8];
int x, y;
bool check(int mid){
memset(f,0,sizeof(f));
for(int i = 1;i <= n;i++){
int sta = 0;
for(int j = 0;j < m;j++)
if(a[i][j] >= mid)sta |= (1 << j);
if(sta == (1 << m) - 1){x = y = i;return true;}
for(int sta1 = sta;sta1;sta1 = sta & (sta1 - 1))
if(f[sta1]){x = f[sta1];y = i;return true;}
f[((1 << m) - 1) ^ sta] = i;
}
// printf("mid = %d\n",mid);
// for(int i = 0;i < (1 << m);i++)printf("sta = %d,f = %d\n",i,f[i]);
return false;
}
signed main(){
n = read(); m = read(); int mx = 0;
for(int i = 1;i <= n;i++)
for(int j = 0;j < m;j++)
mx = max(mx,a[i][j] = read());
int l = 0, r = mx, ans = 0;
while(l <= r){
int mid = l + r >> 1;
if(check(mid)){l = mid + 1;ans = mid;}
else r = mid - 1;
}
check(ans);
printf("%d %d\n",x, y);
return 0;
}
CF1288E
CF1288E题意
一个长度为 \(n\) 的好友列表,自上而下依次是 \(1 \sim n\),你依次收到了 \(m\) 条消息,第 \(i\) 条消息是 \(a_i\) 发来的,这时 \(a_i\) 会跳到会话列表的最上面,其它的按原顺序顺延,求 \(1 \sim n\) 每个好友最靠上的位置和最靠下的位置。
CF1288E题解
很清新的DS题。
维护 \(n+m\) 个位置,每个位置表示有没有数字,然后每次更新答案只会更新调整位置的那个数,想怎么维护怎么维护。
有可能有的数还没被移动,没有更新,最后在扫一遍即可。
CF1288E代码
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 6e5 + 10;
int n, m;
int ansl[maxn],ansr[maxn], pos[maxn];
struct BIT{
int c[maxn << 2];
inline int lowbit(int x){return x & (-x);}
void upd(int x,int upd){for(;x <= n + m;x += lowbit(x))c[x] += upd;}
int qry(int x){int ans = 0;for(;x;x -=lowbit(x))ans += c[x];return ans;}
}tree;
signed main(){
n = read(); m = read();
for(int i = 1;i <= n;i++){
ansl[i] = ansr[i] = i;
pos[i] = i + m;
tree.upd(i + m,1);
}
for(int i = 1;i <= m;i++){
int u = read();ansl[u] = 1;
ansr[u] = max(ansr[u],tree.qry(pos[u]));
tree.upd(pos[u],-1);pos[u] = m - i + 1;
tree.upd(pos[u],1);
}
for(int i = 1;i <= n;i++){ansr[i] = max(ansr[i],tree.qry(pos[i]));}
for(int i = 1;i <= n;i++)printf("%d %d\n",ansl[i],ansr[i]);
return 0;
}

浙公网安备 33010602011771号