iwtgm-16

发布时间 2023-11-07 13:14:38作者: WW爆米花

题目链接

A.

层取,因为它的高度只有2e5,我把每个高度的方格个数记录下来
最后从高到低跑一遍,大于k的ans++
有几个点:
顺序无关紧要,所以先从小到大排个序
从右往左,若前一个与当前的高度相同就continue,直到高度不相同
有一个变量now,记录的是当前高度
把当前高度-1的方格个数就是n-i+1
因为我们是一层一层递减的,且是排好序的,所以当前和当前后面这个高度一定有方格
只要前一个与当前高度不一样,now就不断记录个数然后--
高度数组h[0]的高度是0,一定与其他高度不同
然后要注意的是在最后统计答案时
若tmp+当前高度的个数>k,那么ans++,tmp=当前高度的个数
若==k,tmp=0

ll n,k;
ll h[N];
ll cnt[N];
void solve()
{
    cin>>n>>k;
    ll now=-1,ma;
    ll mi=inf;
    for(int i=1;i<=n;i++){
        cin>>h[i];
        if(h[i]>now)now=h[i];
        if(h[i]<mi)mi=h[i];
    }
    ma=now-1;
    sort(h+1,h+1+n);
    bool f=false;
    for(int i=n;i>=1;i--){
        if(h[i-1]==now)continue;
        while(h[i-1]!=now) {
            cnt[now - 1] = n - i + 1;
            //cout<<"now-1="<<now-1<<' '<<"num="<<n-i+1<<endl;
            now--;
            if(now==mi){
                f=true;break;
            }
        }
        if(f==true)break;
    }
    ll tmp=0,ans=0;
    for(int i=ma;i>=mi;i--){
        if(tmp+cnt[i]<k)tmp+=cnt[i];
        else if(tmp+cnt[i]==k){
            ans++;tmp=0;
        }
        else{
            ans++;
            tmp=cnt[i];
        }
        if(i==mi&&tmp)ans++;
    }
    cout<<ans;
}

B.

设矩形两边分别为a,b
那么就是求4(a+b)^2/(ab)最小
因为(a+b)^2>=0,把括号展开、移项
得到a2+b2>=2ab,当ab时等号成立
可得当a
b的时候也就是正方形的时候是最小的
然后就是让a尽可能接近b,即b/a尽可能小(b>a)
对边长计数,>=4的就输出它
记录所有>=2的边长,看相邻两个谁的b/a最小就输出哪两条

提一嘴错误思路:
分子是平方级的,想着让a,b尽可能小整个分式就能小
这样不无道理但并不全对

#define int long long
ll cnt[N];
vector<ll>v;
void solve()
{
    memset(cnt,0,sizeof(cnt));v.clear();
    int n;cin>>n;
    int success=-1;
    for(int i=1,x;i<=n;i++){
        cin>>x;cnt[x]++;
        if(cnt[x]==2)v.push_back(x);
        if(cnt[x]==4)success=x;
    }
    if(success!=-1){
        for(int i=1;i<=4;i++){
            cout<<success<<' ';
        }
        cout<<endl;return ;
    }
    int ans1,ans2;
    long double mi=inf;
    long double tmp;
    sort(v.begin(),v.end());
    for(int i=1;i<v.size();i++){
        tmp=v[i]*1.0/v[i-1];
        if(tmp<mi){
            mi=tmp;
            ans1=v[i-1];ans2=v[i];
        }
    }
    for(int i=1;i<=2;i++){
        cout<<ans1<<' '<<ans2<<' ';
    }
    cout<<endl;
}

C.

这题自己想了挺多,有两个维度,一个是同种编号的数量,一个是最大读的信息数
并不好对一维排序然后处理另一维
首先这题是求期望,样例给的思路是把所有情况满足条件的人数求个总和再除以钉住的信息数
但这样显然数据量大且不好处理
于是打算根据期望的意义另开辟一条思路
举个例子,有10条信息供你选择,你最多读3条,那么你满足条件的期望就是3/10,跟总和/钉住信息数等价,至此简化了题意
于是我对于每个编号圈了一个集合,枚举钉住信息数量,(必选当前这条信息)我可以得到多大的期望
因为每个人最大阅读信息数量范围只有20,当我钉住信息数量大于20时,那么每条有效期望都是1/钉住信息数
差别只有每个编号集合元素的数量
把每个编号的答案放进答案数组里并按从大到小排序
得到答案:
选一条钉住,就是前一条
两条钉住,就是前两条
...
然后从21枚举到n,逐一比较答案

int n;
struct node{
    int cnt;
    vector<int>v;
};
map<int,node>mp;//编号,k集
int cnt[25];
vector<pair<long double,int>>ans[25];
bool cmp(pair<long double,int> x,pair<long double,int>y){
    return x.first>y.first;
}
int a1,a2;
vector<pair<int,int>>more;
bool cmp1(pair<int,int>x,pair<int,int>y){
    return x.first>y.first;
}
void solve()
{
    cin>>n;
    for(int i=0,id,k;i<n;i++){
        cin>>id>>k;
        mp[id].v.push_back(k);
        mp[id].cnt++;
    }
    for(auto tmp:mp){
        more.push_back({tmp.second.cnt,tmp.first});
        memset(cnt,0,sizeof(cnt));
        for(int i=0;i<tmp.second.v.size();i++){
            cnt[tmp.second.v[i]]++;
        }
        for(int i=1;i<=20;i++){
            long double tm=0;
            for(int j=1;j<=20;j++){
                if(j*1.0/i>1)tm+=1*cnt[j];
                else tm+=j*1.0/i*cnt[j];
            }
            ans[i].push_back({tm,tmp.first});
        }
    }
    for(int i=1;i<=20;i++){
        sort(ans[i].begin(),ans[i].end(),cmp);
    }
    long double tmp=-1;
    for(int i=1;i<=20;i++){
        long double tt=0;
        for(int j=0;j<i&&j<ans[i].size();j++){
            tt+=ans[i][j].first;
        }
        //cout<<"tt="<<tt<<endl;
        if(tt>tmp){
            tmp=tt;
            a1=i;
        }
    }
    sort(more.begin(),more.end(),cmp1);
    int sum=0;
    for(int i=0;i<more.size();i++){
        if(i<20){
            sum+=more[i].first;continue;
        }
        sum+=more[i].first;
        long double tt=sum*1.0/(i+1);
       // cout<<"a2tt="<<tt<<endl;
        if(tt>tmp){
            a2=i+1;tmp=tt;
        }
    }
    if(a2){
        cout<<a2<<endl;
        for(int i=0;i<a2;i++){
            cout<<more[i].second<<' ';
        }
    }
    else {
        int size=ans[a1].size();
        int a11=min(a1,size);
        cout<<a11<<endl;
        for(int i=0;i<ans[a1].size()&&i<a1;i++){
            cout<<ans[a1][i].second<<' ';
        }
    }
}