2020.1.29 寒假训练赛2

https://vjudge.net/contest/354199#overview

A:

简单模拟。

#include<bits/stdc++.h>
using namespace std;

int n,ans;
bool vis[29];
string S;
map<string,bool>ma;
char s[3001];
int num[29]; 

void solve(){
    cin >> n;
    for(int i = 1;i <= n;i ++){
        scanf("%s",s);
        memset(vis,0,sizeof(vis));
        int len = strlen(s),tot = 0;
        S.clear();
        for(int i = 0;i < len;i ++){
            if(vis[s[i] - 'a']) continue;
            num[tot ++] = s[i];
            vis[s[i] - 'a'] = 1;
        }
        sort(num,num + tot);
        for(int i = 0;i < tot;i ++) S += (char)(num[i] + 'a');
        if(!ma[S]) ans ++,ma[S] = 1;
    }
    cout << ans;
    return; 
}

int main(){
    solve();
    return 0;
} 
View Code

B:

题目大意是有14个孔里装着奇数或0个小球,将其中一个孔的小球全部取出依次一个个地放入后面的孔(第14个孔的下一个是第1个孔),不断循环,直到放完。只取一次,最大化有偶数个球的孔的总球数。

简单模拟。。。。

题目理解有偏差,导致WA了5次,某个孔的球取出后,这个孔的球数自然为0.。。。。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 21;
ll num[MAXN],a[MAXN];
void solve(){
    ll ans = 0;
    for(ll i = 1;i <= 14;i ++) scanf("%lld",&num[i]);
    for(ll i = 1;i <= 14;i ++){
        if(num[i]){
            for(ll j = 1;j <= 14;j ++) a[j] = num[j];
            a[i] = 0;
            for(ll j = 1;j <= 14;j ++) a[j] += num[i] / 14;
            ll x = num[i] % 14,f = i;
            for(int j = i + 1;j <= 14 && x;j ++) x -- ,a[j] ++;
            for(int j = 1;j <= x;j ++) a[j] ++;
            ll cnt = 0;
            for(ll j = 1;j <= 14;j ++)
                if(a[j] % 2 == 0) cnt += a[j];
            ans = max(ans,cnt);
        }
    }
    cout << ans;
    return;
}

int main(){
    solve();
    return 0;
} 
View Code

C:

二分

注意某个回合所有战士死亡后,在这一回合立刻复活,且这一回合剩下的箭失效。(WA了一次)

本质就是两个前缀和比较大小,用二分即可。

#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 200001 + 99;
typedef long long ll;
ll k[MAXN],sum[MAXN];
ll n,q,x;
int main(){    
    cin >> n >> q;
    for(int i = 1;i <= n;i ++) scanf("%lld",&x),sum[i] = x + sum[i - 1];
    for(int i = 1;i <= q;i ++){
        scanf("%lld",&k[i]);
        if(k[i] + k[i - 1] >= sum[n]) k[i] = 0;
        else k[i] += k[i - 1];
        ll pos = upper_bound(sum + 1,sum + n + 1,k[i]) - sum;
        printf("%lld\n",n - pos + 1);
    }
    return 0;
}
View Code

抓住本质就很好写了。

D:

简单模拟

对于奇数块,老老实实一刀刀切。

对于偶数块,一刀可以切两块。

注意1块的情况,即不切。(WA了一次)

#include<iostream>
using namespace std;
int main(){
    long long n;
    cin >> n;
    if(n == 0){
        cout << 0 << endl;
        return 0;
    }
    if((n + 1) % 2) cout << n + 1;
    else cout << (n + 1) / 2;
    return 0;
}
View Code

E:

模拟

简化一下题意:有三个字符串,找出beauty最高的字符串。有n次操作,每次操作将任意字母替换为其他字母。

beauty值是字符串中同一字母出现的最大次数。

记原始串同一字母出现最大次数为Max,贪心的思想,其他字母尽量转化成此字母。

两种情况:

1、Max + n <= len     ans = Max + n

2、Max + n  >  len     ans = len;

WA。。。。

考虑对于一个字母,如果对其操作数超过两次,那么它可以转化为任意一个字母(包括它自身),因此情况2一定成立。

但是对于情况1,如果Max = len,即aaaaaaa,n = 1,那么a只能变成其他字母,ans = len - 1。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long ll;
char s[400001];
int num[222];
int cnt[4],pos,n,ans;
void solve(){
    cin >> n;
    for(int i = 1;i <= 3;i ++){
        int Max = -1;
        memset(num,0,sizeof(num));
        scanf("%s",s);
        int len = strlen(s);
        for(int i = 0;i < len;i ++){
            num[s[i]] ++;
            Max = max(num[s[i]],Max);
        }
        if(Max == len && n == 1) cnt[i] = len - 1;
        else if(Max + n <= len) cnt[i] = Max + n;
        else if(Max + n > len) cnt[i] = len;
        if(ans < cnt[i]){
            ans = cnt[i];
            pos = i;
        }
    }
    for(int i = 1;i <= 3;i ++){
        if(cnt[i] == ans && i != pos){
            cout << "Draw";
            return;
        }
    }
    if(pos == 1) cout << "Kuro";
    else if(pos == 2) cout << "Shiro";
    else cout <<"Katie";
    return;
}

int main(){
    solve();
    return 0;
}
View Code

F:

G:

简单模拟

由于是环,间隔数和珍珠数相同,如果链数可均分到每个间隔,则符合。

考虑到珍珠数可能为0,不能做模数,需要特判。。。。。(WA一次)。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char s[201];
int n1,n2;
int main(){    
    scanf("%s",s);
    int len = strlen(s);
    for(int i = 0;i < len;i ++){
        if(s[i] == '-') n1 ++;
        else n2 ++;
    }
    if(!n1 || !n2 || n1 % n2 == 0) cout << "YES";
    else cout << "NO";
    return 0;
}
View Code

H:

构造

在4 * n的图放k个#(障碍),使得左上角到右下角和左下角到右上角最短路径数量相同。

如果k是偶数,显然让图上下对称即可。

如果k是奇数,那么转化一下,从左上角到右下角就等价于从右下角出发到左上角,#放置后,图左右对称即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,k;
char ma[1001][1001];
void solve(){
    cin >> n >> k;
    for(int i = 1;i <= 4;i ++)
        for(int j = 1;j <= n;j ++) 
            ma[i][j] = '.';
    if(k % 2 == 0)
        for(int i = 2;i <= n - 1 && k;i ++,k -= 2)
            ma[2][i] = ma[3][i] = '#';
    else {
        int pos = n / 2 + 1;
        ma[2][pos] = '#';
        int cnt = k / 2;
        for(int i = pos - 1;i >= 2 && cnt;i --)
            ma[2][i] = '#',cnt --;
        cnt = k / 2;
        for(int i = pos + 1;i <= n - 1 && cnt;i ++)
            ma[2][i] = '#',cnt --;
        if(cnt){
            int t = cnt;
            for(int i = pos - 1;i >= 2 && t;i --)
                ma[3][i] = '#',t --;
            t = cnt;
            for(int i = pos + 1;i <= n - 1 && t;i ++)
                ma[3][i] = '#',t --;
        }
    }
    cout << "YES" << endl;
    for(int i = 1;i <= 4;i ++){
        for(int j = 1;j <= n;j ++){
            cout << ma[i][j];
        }
        cout << endl;
    }
}

int main(){
    solve();
    return 0;
}
View Code

I:

J:

数论?

从$\sqrt{n}$枚举到1,判断即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath> 
using namespace std;
typedef long long ll;
ll n;
ll calc(ll a){
    ll num = 0;
    while(a) num ++,a /= 10;
    return num;
}
void solve(){
    cin >> n;
    for(ll i = sqrt(n);i >= 1;i --){
        if(n % i == 0){
            cout << max(calc(i),calc(n / i)) << endl;
            return;
        }
    }
    return;
}

int main(){
    solve();
    return 0;
}
View Code

K:

数学

首先从大到小排序,则前A个数可以取到最大平均值。

两种情况讨论:

cnt[a[i]] : 第i个数出现的次数。

1、前A个数相同(均为最大的数),令$t = min\left ( cnt[a[A]] ,B\right )$,答案为$\sum_{i = A}^{t}C_{cnt[a[A]]}^{i}$

2、前A个数不同,记count为前A个数a[A]出现的次数。答案为$C_{cnt[a[A]]}^{count}$

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const ll MAXN = 1001;
ll sum[MAXN],a[MAXN];
ll n,A,B;
ll dp[MAXN][MAXN];
map<ll,ll>ma;
void C(){
    dp[1][1] = 1;
    for(ll i = 0;i <= 151;i ++) dp[i][0] = 1;
    for(ll i = 2;i <= 151;i ++)
        for(ll j = 1;j <= 151;j ++)
            dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]; 
}

bool cmp(ll a,ll b){
    return a > b;
}

void solve(){
    C();
    cin >> n >> A >> B;
    for(ll i = 1;i <= n;i ++)
        scanf("%lld",&a[i]),ma[a[i]] ++;
    sort(a + 1,a + n + 1,cmp);
    ll sum = 0;
    double pingjun = 0.0;
    for(ll i = 1;i <= A;i ++) sum += a[i];
    pingjun = (double)sum / (double)A;
    ll pos = 0;
    for(ll i = A;i >= 1;i --){
        if(a[i] != a[i - 1]){
            pos = i;
            break;
        }
    }
    ll ans = 0;
    if(pos == 1)
        for(int i = A;i <= B;i ++) ans += dp[ma[a[A]]][i];
    else ans = dp[ma[a[A]]][A - pos + 1];
    printf("%.8lf\n",pingjun);
    printf("%lld\n",ans);
    return;
}
int main(){
    solve();
    return 0;
}
View Code

L:

贪心

让奇数和4的倍数相邻即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,f1,f2,f3;
void solve(){
    int x;
    cin >> n;
    for(int i = 1;i <= n;i ++){
        scanf("%d",&x);
        if(x % 4 == 0) f1 ++;
        else if(x % 2 == 0) f2 ++;
        else f3 ++;
    }
    if(!f2 && f3 == f1 + 1) cout << "Yes" << "\n";
    else if(f1 >= f3) cout << "Yes" << endl;
    else cout << "No" << endl;
}

int main(){
    solve();
    return 0;
}
View Code

M:

模拟

S型放置数字即可。

例如:

5 5 5 5 5

5 4 4 4 4 

2 3 3 3 4

2 2 2 1 1

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 1204;
int h,w,n;
int ma[MAXN][MAXN],a[20001];
void solve(){
    cin >> h >> w >> n;
    for(int i = 1;i <= n;i ++)
        cin >> a[i];
    int tot = n;
    for(int i = 1;i <= h;i ++){
        if(i % 2){
            for(int j = 1;j <= w;j ++){
                ma[i][j] = tot,a[tot] --;
                if(a[tot] == 0) tot --;
            }
        }
        else{
            for(int j = w;j >= 1;j --){
                ma[i][j] = tot,a[tot] --;
                if(a[tot] == 0) tot --;
            }
        } 
    }
    for(int i = 1;i <= h;i ++){
        for(int j = 1;j <= w;j ++){
            cout << ma[i][j] << " ";
        }
        cout << endl;
    }
    return;
}

int main(){
    solve();
    return 0;
} 
View Code

猜你喜欢

转载自www.cnblogs.com/cgold/p/12242336.html