A - Binary Decimal
思路:
直接看十进制数的每一位最高为多少
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
void solve() {
int n;scanf("%d",&n);
int ans = 0;
while(n) {
ans = max(ans,n % 10);
n /= 10;
}
printf("%d\n",ans);
}
int main() {
int T;scanf("%d",&T);
while(T--) solve();
return 0;
}
B - Putting Plates
思路:
直接照着样例模拟就行,注意下边界情况能否放1的判断。
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
int mp[30][30];
void solve() {
int n,m;
cin >> n >> m;
for(int i = 1;i <= n;i ++) for(int j = 1;j <= m;j ++) mp[i][j] = 0;
if((n % 2 == 1) && (m % 2 == 1)) {
for(int j = 1;j <= m;j += 2) {
mp[1][j] = 1;
}
for(int j = 1;j <= m;j += 2) {
mp[n][j] = 1;
}
for(int i = 1;i <= n;i += 2) {
mp[i][1] = 1;
}
for(int i = 1;i <= n;i += 2) {
mp[i][m] = 1;
}
}
else if((n % 2 == 0) && (m % 2 == 0)) {
for(int j = 2;j <= m - 2;j += 2) {
mp[1][j] = 1;
}
for(int j = 3;j <= m;j += 2) {
mp[n][j] = 1;
}
for(int i = 3;i <= n;i += 2) {
mp[i][1] = 1;
}
for(int i = 2;i <= n - 2;i += 2) {
mp[i][m] = 1;
}
}
else if((n % 2 == 1 && m % 2 == 0)) {
for(int j = 2;j <= m;j += 2) {
mp[1][j] = 1;
}
for(int j = 1;j <= m;j += 2) {
mp[n][j] = 1;
}
for(int i = 3;i <= n;i += 2) {
mp[i][1] = 1;
}
for(int i = 1;i <= n - 2;i += 2) {
mp[i][m] = 1;
}
}
else if((n % 2 == 0 && m % 2 == 1)) {
for(int j = 1;j <= m - 2;j += 2) {
mp[1][j] = 1;
}
for(int j = 3;j <= m;j += 2) {
mp[n][j] = 1;
}
for(int i = 1;i <= n;i += 2) {
mp[i][1] = 1;
}
for(int i = 2;i <= n;i += 2) {
mp[i][m] = 1;
}
}
for(int i = 1;i <= n;i ++) {
for(int j = 1;j <= m;j ++) {
printf(j == m ? "%d\n" : "%d",mp[i][j]);
}
}
puts("");
}
int main() {
int T;scanf("%d",&T);
while(T--) solve();
return 0;
}
C - Pursuit
思路:
看到要求最小的额外场次且每次\(check\)比较容易的\(O(n)\)判断,我就直接二分了,赛后得知可能一遍处理一下即可。
预处理一下得分的和,然后二分需要的场次即可。
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 1e5 + 10;
int a[N],b[N],suma[N],sumb[N],n;
bool cmp(int x,int y) {
return x > y;
}
bool check(int x) {
int num = n + x - (n + x) / 4;//需要进行的场数
ll sum1,sum2;
if(x >= num) {
sum1 = num * 100,sum2 = sumb[min(n,num)];
}
else {//额外小于需要
sum1 = x * 100 + suma[num - x],sum2 = sumb[min(n,num)];
}
if(sum1 >= sum2) return true;
else return false;
}
void solve() {
scanf("%d",&n);
for(int i = 1;i <= n;i ++) suma[i] = sumb[i] = 0;
for(int i = 1;i <= n;i ++) {
scanf("%d",&a[i]);
}
for(int i = 1;i <= n;i ++) {
scanf("%d",&b[i]);
}
sort(a + 1,a + 1 + n,cmp);
sort(b + 1,b + 1 + n,cmp);
for(int i = 1;i <= n;i ++) suma[i] = a[i] + suma[i - 1];
for(int i = 1;i <= n;i ++) sumb[i] = b[i] + sumb[i - 1];
int l = 0,r = 10000000,ans;
while(l <= r) {
int mid = (l + r) >> 1;
// cout << l << ' ' << r << '\n';
if(check(mid)) {
r = mid - 1;
ans = mid;
// cout << mid << "-----\n";
}
else {
l = mid + 1;
}
}
printf("%d\n",ans);
}
int main() {
int T;scanf("%d",&T);
while(T--) solve();
return 0;
}
D - Secret Santa
题意:
一共有\(n\)个人,他们之间要相互赠送礼物,在赠送的过程中呢,每个人只能给一个送礼物,但不能送给自己,每个人必须且只能收到一份礼物。
对于第\(i\)个人,\(a_i\)表示这个人期望把礼物送给谁,多个人可能期望把礼物送给同一个人,现在需要你给出一种方案使得满足礼物期望的人数尽可能的多。
思路:
①
这道题好像乱搞就可直接过。
直接处理出,在期望送礼物的人选中,没有出现的人是哪些,对于\(i\)来说,如果\(a_i\)只出现了一次,那么丛贪心的角度考虑,我们就一定要把\(i\)的礼物送给\(a_i\)。
我们从小到大枚举,如果当前的\(i\)的\(a_i\)出现次数多于一次,那么我们就从预处理的未被指定的集合中,从大到小的挑选\(i\)送礼物的合法人选,如果都没有合法选择,那么我们只能维持它的送礼对象不变,因为两边是对着枚举,所以是可行的。
但其实这么做的正确性也是感性理解的,并不会证明
★★★②
也可以从图的角度来考虑这个问题,假如我们从\(i\)向\(a_i\)连一条有向边,那么所有的\(i\)和\(a_i\)就会行成一个有向图。
然后我们只需要用\(dfs\)从图的每个入度为0的点进行图的遍历,每次都会形成一条路径。
这里比较关键的就是,路径的起点一定要选择入度为0的点,这样就保证了不会把某个点单独的割裂出来而形成的不合法局面。
例如这样的图,我们一定要从\(4\)开始出发,否则就会把点\(4\)孤立出来造成不合法的局面。
随后完成路径的拼接即可。
方法①的代码:
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 2e5 + 10;
int n,a[N],ans[N],vis[N],readylist[N];
void solve() {
cin >> n;
for(int i = 1;i <= n;i ++) ans[i] = vis[i] = 0;
for(int i = 1;i <= n;i ++) {
cin >> a[i];
vis[a[i]]++;
}
int used = 0,tot = 0;
for(int i = 1;i <= n;i ++) {
if(!vis[i]) {
readylist[++used] = i;
}
}
int cnt = used;;
for(int i = 1;i <= n;i ++) {
if(vis[a[i]] > 1 && readylist[used] != i) {//一定是对着来换应该会更优
ans[i] = readylist[used--];
vis[a[i]]--;
}
else {//能换就先换掉 不能换就不管了
ans[i] = a[i];
}
}
printf("%d\n",n - cnt);
for(int i = 1;i <= n;i ++) {
printf(i == n ? "%d\n" : "%d ",ans[i]);
}
}
int main() {
int T;cin >> T;
while(T--) solve();
return 0;
}
方法②代码:
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 2e5 + 10;
int ans,tot,a[N],path[N],e[N],n,s[N],f[N];//s代表每条路径的起点,f代表终点
void dfs(int u) {
path[u] = tot;
if(path[a[u]] == 0) {
dfs(a[u]);
}
else {
f[tot] = u;
ans--;//每条路径都会有一个点是不能满足要求的 即n个点只能满足n-1个需求
}
}
void solve() {
scanf("%d",&n);
for(int i = 1;i <= n;i ++) e[i] = 0;
for(int i = 1;i <= n;i ++) {
scanf("%d",&a[i]);
e[a[i]] = 1;
path[i] = 0;
}
ans = n,tot = 0;
for(int i = 1;i <= n;i ++) {
if(!e[i]) {//这个点无入度
s[++tot] = i;
dfs(i);
}
}
// for(int i = 1;i <= tot;i ++) {
// cout << "start = " << s[i] << ' ' << "end = " << f[i] << '\n';
// }
if(tot > 0) {//把路径之间拼接起来
for(int i = 1;i < tot;i ++) {
a[f[i]] = s[i+1];
}
a[f[tot]] = s[1];
}
printf("%d\n",ans);
for(int i = 1;i <= n;i ++) {
printf("%d%c",a[i],i==n?'\n':' ');
}
}
int main() {
int T;scanf("%d",&T);
while(T--) {
solve();
}
return 0;
}