sduwh xcpc选拔赛(2)
A 《签到题》
开局被这个签到题搞心态了 md
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
int main(){
int n,x,c,ans=0;
cin>>n>>x>>c;
for(int i=1;i<=n;i++){
int xx;
cin>>xx;
if(xx<c)continue;
if(abs(xx-x)<=3)ans++;
}
if(x<c)cout<<"0"<<endl;
else
cout<<ans<<endl;
return 0;
}
F 《数金币》
分析:
开始以为是中国剩余定理 打了一遍 才发现数据太大了
发现只需要枚举一下就好了了 注意从0开始
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=1e3+5;
ll a[maxn],b[maxn];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)scanf("%lld %lld",&a[i],&b[i]);
for(int i=1;i<=100000;i++){
int pd=1;
for(int j=1;j<=n;j++)
if((i%a[j])!=b[j]){
pd=0;
break;
}
if(pd){
cout<<i;
return 0;
}
}
cout<<"SO RICH!";
return 0;
}
D 《爆金币》
分析:
开始以为是什么很高级的题目
结果其实就是排序
队员的值很小 桶排序 队长的人数少但是数值大 直接排序
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=1e3+5;
const int maxm=1e5+5;
int n,k,cnt;
int Q[maxn],res[maxm];
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
int xx,yy;
scanf("%d%d",&xx,&yy);
for(int j=yy;j>=1;j--){
int p=xx%j;
Q[p]++;
xx-=p;
}
if(xx<100)
Q[xx]++;
else res[++cnt]=xx;
}
if(k<=cnt){
sort(res+1,res+1+cnt);
cout<<res[cnt-k+1];
return 0;
}
int sum=0;
k-=cnt;
for(int i=99;i>=0;i--){
if(sum+Q[i]>=k){
cout<<i<<endl;
return 0;
}
sum+=Q[i];
}
return 0;
}
B 《挖金币》
分析:
很好想到是并查集 但是比赛不知道怎么连边
1 对于同行点的 所在列 合并为一堆(两列能共享剩下的点) ans的一部分即为堆数-1
2 对于剩下没有点的行 每行只需要一个点即可
ans=空行+堆数-1
#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline T next() {
T x;
cin >> x;
return x;
}
void untie() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
using LL = long long;
void solve() {
int n = next<int>();
int m = next<int>();
int k = next<int>();
vector<int> mark(n + 1);
vector<int> fa(m + 1);
for (int i = 1; i <= m; i++) {
fa[i] = i;
}
function<int(int)> getf = [&](int x) -> int {
return fa[x] == x ? x : (fa[x] = getf(fa[x]));
};
for (int i = 1; i <= k; i++) {
int x = next<int>();
int y = next<int>();
if (mark[x]) {
fa[getf(y)] = getf(mark[x]);
}
mark[x] = y;
}
int ans = -1;
for (int i = 1; i <= m; i++) {
ans += fa[i] == i;
}
for (int i = 1; i <= n; i++) {
ans += mark[i] == 0;
}
cout << ans << '\n';
}
int main() {
untie();
int T = 1; // next<int>();
while (T--) {
solve();
}
return 0;
}
E 《矩阵填数》
分析:
很容易想到奇数和偶数分为两部分 关键点在于分界线不好处理
对于n=3,4,5手动处理
对于n>=6 3的奇数倍和偶数倍个数都>=n
将3的奇数倍和偶数倍分别组合
比赛的时候sb了 没有想到倍数来组合非质数
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
int n;
cin >> n;
vector<vector<int>> A(n, vector<int>(n));
if(n == 3) {
A[0] = {5, 9, 1};
A[1] = {3, 7, 8};
A[2] = {6, 2, 4};
}
if(n == 4) {
A[0] = { 9, 11, 13, 15};
A[1] = { 1, 3, 5, 7};
A[2] = { 8, 6, 4, 2};
A[3] = {10, 12, 14, 16};
}
if(n == 5) {
A[0] = { 5, 7, 11, 13, 17};
A[1] = {19, 23, 25, 21, 1};
A[2] = { 3, 9, 15, 24, 8};
A[3] = { 6, 12, 18, 2, 4};
A[4] = {10, 14, 16, 20, 22};
}
if(n >= 6) {
vector<int> B;
for(int x = 1; x <= n * n; ++ x)
if(x % 2 == 1 && x % 3 != 0)
B.push_back(x);
for(int x = 1; x <= n * n; ++ x)
if(x % 2 == 1 && x % 3 == 0)
B.push_back(x);
for(int x = 1; x <= n * n; ++ x)
if(x % 2 == 0 && x % 3 == 0)
B.push_back(x);
for(int x = 1; x <= n * n; ++ x)
if(x % 2 == 0 && x % 3 != 0)
B.push_back(x);
for(int i = 0; i < n; ++ i)
for(int j = 0; j < n; ++ j)
A[i][j] = B[n * i + j];
}
for(int i = 0; i < n; ++ i)
for(int j = 0; j < n; ++ j)
cout << A[i][j] << " \n"[j == n - 1];
return 0;
}
C 子序列
分析:
一道非常好的题目
已知pi 的倍数的位置 可以为q[i1] q[i2]....q[ik]
从p1顺序处理到pn
对于每个pi 选择一个q[i] 使得递增 最终使得长度最大
不难想到最长上升子序列问题
代码写的很清楚
#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline T next() {
T x;
cin >> x;
return x;
}
void untie() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
using LL = long long;
void solve() {
int n = next<int>();
vector<int> a(n + 1);
vector<int> b(n + 1);
a[i] = next<int>();
}
for (int i = 1; i <= n; i++) {
b[next<int>()] = i;
}
vector<int> atree(n + 1);
auto add = [&](int x, int v) -> void {
for (int i = x; i <= n; i += i & -i) {
atree[i] = max(atree[i], v);
}
};
auto query = [&](int x) -> int {
int ans = 0;
for (int i = x; i; i -= i & -i) {
ans = max(ans, atree[i]);
}
return ans;
};
for (int i = 1; i <= n; i++) {
set<pair<int, int>> op;
for (int j = a[i]; j <= n; j += a[i]) {
int p = b[j];
int v = query(p - 1) + 1;
op.insert(make_pair(p, v));
}
for (auto pv : op) {
add(pv.first, pv.second);
}
}
cout << query(n) << '\n';
}
int main() {
untie();
int T = 1; // next<int>();
while (T--) {
solve();
}
return 0;
}