codeforces #561补题

A.题意:第一个字母相同的的人放在一个教室会聊天,给出一些人的名字,问如何将他们分配到两个教室,使得聊天的pair对最少…
挺水的一个题,只要将同名的人平均分到两个教室就可以了。

#include <iostream>
#include <cmath>
using namespace std;
int arr[30];
int Cal(int n){
    if(!n) return 0;
    return n*(n-1)/2;
}
int main()
{
    int n;  cin >> n;
    string str;
    for(int i = 0; i < n; ++i){
        cin >> str;
        ++arr[str[0]-'a'];
    }
    int tot = 0;
    for(int i = 0; i < 26; ++i){
        int maxx = ceil(arr[i]*1.0/2);
        tot += Cal(maxx) + Cal(arr[i]-maxx);;
    }
    cout << tot << endl;
    return 0;
}

B.使得每一行每一列都会出现所有的元音字母
很容易想到当 n <5的时候肯定不满足,所以考虑n>=5的时候,然后构造一下就好了

#include <iostream>
using namespace std;
char cc[105][105];
char yuan[5] = {'a','e','i','o','u'};
int main()
{
    int k;  cin >> k;
    int row = 0,col = 0 ;
    for(int i = 5; i < k; ++i){
        if(!(k%i)){
            row = i,col = k/i;
            break;
        }
    }
    if(row < 5 || col < 5){
        cout << -1 << endl;
        return 0;
    }
    int tot = 0;
    for(int i = 0; i < row; ++i){
        for(int j = 0; j < col; ++j){
            cc[i][j] = yuan[(i+j)%5];
        }
    }
    for(int i = 0; i < row; ++i){
        for(int j = 0; j < col; ++j){
            if(cc[i][j]=='\0'){
            }
            else cout << cc[i][j];;
        }
    }
    cout << endl;

    return 0;
}

C.题意指的是 给你一些数字,让你找出 pair(x,y) 使得 m i n ( ∣ x − y ∣ , ∣ x + y ∣ ) &lt; = ∣ x ∣ &lt; = ∣ y ∣ &lt; = m a x ( ∣ x + y ∣ , ∣ x − y ∣ ) min(|x-y|,|x+y|)&lt;=|x|&lt;=|y|&lt;=max(|x+y|,|x-y|) min(xy,x+y)<=x<=y<=max(x+y,xy)
那么对于每个数来说可以将上述式子平方转换一下得到 x x x y y y的关系式
当时做的时候考虑了正负(最后好像是没有影响的只要取绝对值后直接分析即可)
最后记得加longlong,会溢出的…

#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
struct Node{
    long long l,r;
};
const long long MAX = 2e5+5;
long long arr[MAX];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    map<long long,Node> mp;
    long long n;  cin >> n;
    for(long long i = 0; i < n; ++i)  cin >> arr[i];
    sort(arr,arr+n);
    for(long long i = 0; i < n; ++i){
        mp[arr[i]].l = min(i,mp[arr[i]].l);
        mp[arr[i]].r = max(i,mp[arr[i]].r);
    }
    long long tot = 0;
    for(long long i = 0; i < n; ++i){
        if(arr[i]>0){ // 如果是正数 先找一个最大值2*x的位置
            long long rr = upper_bound(arr,arr+n,arr[i]*2)-arr-1;
            tot += abs(rr - i);
            // 再考虑异号的(一定要满足 y <= -2x) 假设 y = arr[i] 即 -y <= x <= y/-2; 这里把正数当作y
            // 第二种 x = arr[i] y>=-2x  && y <= -x         即    -2y <= x <= y/-2;
            long long xx = upper_bound(arr,arr+n,arr[i]*1.0/-2)-arr;
            long long yyy = lower_bound(arr,arr+n,-2*arr[i])-arr;
            tot += (xx-yyy);
        }
        if(arr[i]<=0){
            // 把arr[i] 看成是 x 的话 要找到 一个y>=2x的位置
            // 只考虑同号的情况
            long long rr = lower_bound(arr,arr+n,arr[i]*2)-arr;
            tot += i-rr;

        }
    }
    cout << tot <<endl;
    return 0;
}

D题

E题也是个思维题来着…也涉及到一些数论知识吧
这题的意思是: 每天买 k i k_i ki个物品,但是不记得每个商店里的物品权值 a i a_i ai,问你有没有可能存在一组 a i a_i ai使得每一天选择的 k i k_i ki个物品的 L C M LCM LCM都大于其补集的 L C M LCM LCM,其中LCM的定义是 一个最小整数使得他能被这个整数集合的所有元素整除

结论: 如果两两集合都存在交集,那么就 p o s s i b l e possible possible,反之 i m p o s s i b l e impossible impossible

首先假设两两集合不存在交集
总集合是 ( a , b , c , d , e ) (a,b,c,d,e) (a,b,c,d,e) 那么第一天选择的集合是 ( a , b ) (a,b) (a,b),那么其补集就是 ( c , d , e ) (c,d,e) (c,d,e)
要满足 L C M ( a , b ) &gt; L C M ( c , d , e ) LCM(a,b) &gt; LCM(c,d,e) LCM(a,b)>LCM(c,d,e)
那么再考虑第二天选择的是 ( c , d ) (c,d) (c,d),其补集就是 ( a , b , e ) (a,b,e) (a,b,e) 要满足 L C M ( c , d ) &gt; L C M ( a , b , e ) LCM(c,d)&gt;LCM(a,b,e) LCM(c,d)>LCM(a,b,e)
但是很显然 L C M ( a , b , e ) &gt; = L C M ( a , b ) LCM(a,b,e) &gt;= LCM(a,b) LCM(a,b,e)>=LCM(a,b) L C M ( c , d , e ) &gt; = L C M ( c , d ) LCM(c,d,e) &gt;= LCM(c,d) LCM(c,d,e)>=LCM(c,d) 于是就产生了矛盾

所以最终只需要判断每两天之间是不是存在交集就可以了

#include <iostream>
#include <vector>
#include <set>
using namespace std;
const int MAX = 1e4+5;
set<int>st[MAX];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int m,n;    cin >> m >> n;
    for(int i = 0,k; i < m; ++i){
        cin >> k;
        for(int j = 0,x; j < k; ++j){
            cin >> x;
            st[i].insert(x);
        }
    }

    for(int i = 0; i < m; ++i){
        for(int j = i+1; j < m; ++j){
            bool ishave = false;
            for(auto y : st[i]){
                if(st[j].count(y)){
                    ishave = true;
                    break;
                }
            }
            if(!ishave){
                cout << "impossible" << endl;
                return 0;
            }
        }
    }
    cout << "possible" << endl;
    return 0;
}

F

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值