cf训练2

CF 616 div1

A

题解

若 \(k \geq m-1\) ,我们可以任意指定顺序,我们求每个方案的最大值即可。

若 \(k < m-1\) ,发现我们有 \(m - k\) 种可能,取最小值即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
int read()
{
    int k=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) k=k*10+c-'0';return k*f;
}
const int N=5005;
int n,m,k,T,a[N];
int main()
{
    for(T=read();T;T--)
    {
        n=read();m=read();k=read();
        for(int i=1;i<=n;i++)
            a[i]=read();
        if(k>=m-1)
        {
            int ans=0;
            for(int i=1;i<=m;i++)
                ans=max(ans,max(a[i],a[n-m+i]));
            printf("%d\n",ans);
            continue;
        }
        else
        {
            int ans=0,x=m-1-k;
            for(int i=0;i<=k;i++)
            {
                int as=0x7fffffff;
                for(int j=i+1;j<=i+x+1;j++)
                    as=min(as,max(a[j],a[n-m+j]));
//              cout<<as<<endl;
                ans=max(ans,as);
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

    

B

题解

我们发现如果字符串最左和最右的字符不同,那么一定可以有 irreducible anagram ,我们把首尾换一下就行。 如果相同,且字符种类大于等于三,我们找到最后一个与末尾字符不同的字符 $s[k] \neq s[n] $ ,把 \(s[k]\) 的所有字符放在最前面,再放 \(s[n]\) 的所有字符,最后把剩余字符随意摆放,这样就的串就是Irreducible Anagrams 。

当字符种类小于三时,显然不存在 Irreducible Anagrams。

统计一下每个字符的前缀和就可以了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
int read()
{
    int k=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) k=k*10+c-'0';return k*f;
}
const int N=200055;
int n,a,b,sum[N][26];
char s[N];
int main()
{
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;i++)
    {
        memcpy(sum[i],sum[i-1],sizeof(sum[i]));
        sum[i][s[i]-'a']++;
    }
    n=read();
    for(int i=1;i<=n;i++)
    {
        a=read();b=read();
        if(a==b) puts("Yes");
        else if(s[a]!=s[b]) puts("Yes");
        else
        {
            int cnt=0;
            for(int j=0;j<26;j++)
                if(sum[b][j]-sum[a-1][j])
                    cnt++;
            if(cnt>2) puts("Yes");
            else puts("No");
        }
    }
    return 0;
}

C

题解

首先,每一盏灯最多在两个集合里,如果在一个或不在集合里,对该灯的操作是确定的。

接下来重点讨论在两个集合的做法,发现,不管灯是亮的还是灭的,我们都只有两种操作方法,亮的:一个操作一个不操作,灭的:都操作或都不操作。

我们可以用并查集维护集合,\(1 - m\) 表示对集合操作,\(m+1 - 2m\) 表示对集合不操作,我们按顺序开灯,同时处理并查集的关系并计算答案。 细节见代码。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define ll long long
using namespace std;
int read()
{
    int k=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) k=k*10+c-'0';return k*f;
}
const int N=600055;
int n,m,a[N],fa[N],size[N],c[N][3],fl[N];
char s[N];
int find(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
int get(int x)
{
    int a=find(x),b=find(x+m);
    if(fl[a]) return size[a];
    if(fl[b]) return size[b];
    return min(size[a],size[b]);
}
int main()
{
    n=read();m=read();
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
        a[i]=s[i]-'0';
    for(int i=1;i<=m;i++)
    {
        int x=read();
        for(int j=1;j<=x;j++)
        {
            int y=read();
            c[y][++c[y][0]]=i;
        }
    }
    int now=0;
    for(int i=1;i<=m*2;i++)
        fa[i]=i,size[i]=(i<=m);
    for(int i=1;i<=n;i++)
    {
        if(c[i][0]==1)
        {
            now-=get(c[i][1]);
            if(a[i]) fl[find(c[i][1]+m)]=1;
            else fl[find(c[i][1])]=1;
            now+=get(c[i][1]);
        }
        else if(c[i][0]==2)
        {
            int x=find(c[i][1]),y=find(c[i][2]),z=find(c[i][1]+m),w=find(c[i][2]+m);
            if(!a[i]&&x!=w)
            {
                now-=get(c[i][1])+get(c[i][2]);
                if(w!=x) size[w]+=size[x];fl[w]|=fl[x];fa[x]=w;
                if(z!=y) size[z]+=size[y];fl[z]|=fl[y];fa[y]=z;
                now+=get(c[i][1]);
            }
            else if(a[i]&&x!=y)
            {
                now-=get(c[i][1])+get(c[i][2]);
                if(x!=y) size[y]+=size[x],fl[y]|=fl[x];fa[x]=y;
                if(z!=w) size[z]+=size[w],fl[z]|=fl[w];fa[w]=z;
                now+=get(c[i][1]);
            }
        }
        printf("%d\n",now);
    }
    return 0;
}

D

题解

\(k=1\) 时,我们逐个对比就行。

$ k \neq 1$ 时,我们把咖啡按 \(k/2\) 的大小分组,逐组比较,把记得的咖啡打上标记,最后统计没有标记的数目就是答案,这样就可以做到 $ \frac{2n^2} {k} $ 。

继续优化,我们发现先尝第一组,第二组,再尝第三组。相当于对比了一二组和二三组。不用清空记忆。那么我们把上面的方案改变顺序,连续品尝即可。先 $ 1\quad 2 \quad 3 ... n$ ,相当于问了$ 1,2 \quad 2,3 \quad 3,4\quad ...n-1,n$ ,再 $ 1 \quad 3 \quad ....n-1$ ,$ 2 \quad 4 \quad .... n$ ,每次问完一大组再清空。

询问次数 $ \frac{3n^2} {2k} $ 。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#define ll long long
using namespace std;
int read() {
    int k=0,f=1;
    char c=getchar();
    for(; !isdigit(c); c=getchar()) if(c=='-') f=-1;
    for(; isdigit(c); c=getchar()) k=k*10+c-'0';
    return k*f;
}
const int N=1550;
int n,m,cnt[N];
char s;
vector<int> V;
int main() {
    cin>>n>>m;
    fflush(stdout);
    if(m==1) {
        int now=0;
        for(now=1; now<=m+1&&now<=n; now++) {
            cout<<"? "<<now<<endl;
            fflush(stdout);
            cin>>s;
            if(s=='N') V.push_back(now);
        }
        cout<<"R\n";
        for(int i=now; i<=n; i++) {
            cout<<"? "<<i<<endl;
            fflush(stdout);
            cin>>s;
            int fl=1,now=0;
            for(int j=0; j<V.size(); j++) {
                now++;
                cout<<"? "<<V[j]<<endl;
                fflush(stdout);
                cin>>s;
                if(s=='Y') {
                    fl=0;
                    break;
                }
                if(now==m) {
                    cout<<"R\n";
                    fflush(stdout);
                    cout<<"? "<<i<<endl;
                    fflush(stdout);
                    cin>>s;
                    now=0;
                }
            }
            if(fl) V.push_back(i);
            cout<<"R\n";
            fflush(stdout);
        }
        cout<<"! "<<V.size()<<endl;
        fflush(stdout);
    } else {
        int si=m/2,bl=n/si;
        for(int i=1; i<bl; i++)
            for(int j=1; j<=i&&j+i<=bl; j++) {
                cout<<"R\n";
                for(int k=j; k<=bl; k+=i)
                    for(int p=(k-1)*si+1; p<=k*si; p++)  {
                        cout<<"? "<<p<<endl;
                        fflush(stdout);
                        cin>>s;
                        if(s=='Y') cnt[p]=1;
                    }
            }
        int ans=0;
        for(int i=1; i<=n; i++)
            if(!cnt[i]) ans++;
        cout<<"! "<<ans<<endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/waing/p/12264186.html

时间: 2024-08-04 02:50:47

cf训练2的相关文章

CUGBACM Codeforces Tranning 3 题解

链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=62515#overview 描述:第三场CF训练了,这次做的挺搞笑的,我记得这是内天持续训练九个小时中的最后两个小时,想想也是蛮拼的. 题解: A.Triangle 题意:给四个边,如果能组成判断能不能从其中找三条边组成三角形,不就再判断能不能三条边首尾相接组成一个线段. 思路:三角形判断条件,两条边之和大于第三条边,两边之和等于第三条边就是线段. 代码: #include <al

暑假集训-8.14总结

学习内容:线段树 今日完成题数:8 今日看书情况:208~214页 学习算法的总结: 今日做题总结: https://www.cnblogs.com/Lis-/p/11354349.html 今日心得: 学新算法时要多写题. 线段树更新.查询时要注意写法. 还是要多写cf训练思维. 原文地址:https://www.cnblogs.com/l999q/p/11354719.html

音乐推荐系统实践

一.推荐系统流程图 CB,CF算法在召回阶段使用,推荐出来的item是粗排的,利用LR算法,可以将CB,CF召回回来的item进行精排,然后选择分数最高,给用户推荐出来. 二.推荐系统思路详解 代码思路: 1.数据预处理(用户画像数据.物品元数据.用户行为数据) 2.召回(CB.CF算法) 3.LR训练模型的数据准备,即用户特征数据,物品特征数据 4.模型准备,即通过LR算法训练模型数据得到w,b 5.推荐系统流程: (1)解析请求:userid,itemid(2)加载模型:加载排序模型(mod

HDU-SupportOrNot训练实录

菜鸡队训练实录. 现场赛记录: 2016:[名称:奖项/排名] ZJPSC:Gold/1 CCPC中南邀请赛:Gold/1 ICPC Dalian:Gold/24 ICPC Beijing:??? CCPC Final:??? ICPC China-Final:??? To do List: 所有人需要提高效率 减小罚时 三人组队训练时必须用指定Ubuntu电脑敲题,其他两台电脑只能读题.读代码 为提升代码能力,poursoul和_ilovelife尽量做到每天solo一套简单GYM,也可以视情

《程序员的思维训练》

<程序员的思维训练> <程序员的思维修炼:开发认知潜能的九堂课> 从程序员的角度去认清自己,思考问题,了解我们的大脑,进而发掘潜能. 作者是亨特(Andy Hunt),他曾经写过<程序员修炼之道——从小工到专家>,<高效程序员的45个习惯:敏捷开发修炼之道>,<Programming Ruby>,<单元测试之道C#版——使用NUnit >.<单元测试之道Java版——使用JUnit>.<版本控制之道——使用CVS &

组队训练1 回放

第一场组队训练--意料之中的爆炸. 开场先看题,H是斐波那契水题,qw把H切了. 同时czy看I题(排列),cst继续读其他题. czy尝试交I,PE. cst发现K是水题. cst上来敲K,WA.回去检查. czy继续干I,还是没过. cst又交了一发K,WA. czy交了一发I, 终于过了. cst把K交给了czy之后去看其他题. 与此同时qw开敲C,一发就过. D题看起来像个递推规律题. cst猜D结论,WA(事实上这个结论样例都过不去)czy交K,AC(之前cst把题目理解错了) cst

我要cf破1000题!!!

我现在cf是292题,还差1000-292=708题. 水平的提高确实和题数不完全相关,但是问题是现在训练强度确实太低了. 我打算在两个月之内达到1000题,也就是说1天至少10题,两个月60天,720/60=12题/天,平均每天做12题就完成任务了. 为了提高效率,我应该不会在一道题卡两个小时以上,会直接看题解,保证平均40分钟补一个题.

zz [Recommendation System] 推荐系统之协同过滤(CF)算法详解和实现

http://yidianzixun.com/n/09vv1FRK?s=1 完全摘抄自网页 1 集体智慧和协同过滤 1.1 什么是集体智慧(社会计算)? 集体智慧 (Collective Intelligence) 并不是 Web2.0 时代特有的,只是在 Web2.0 时代,大家在Web 应用中利用集体智慧构建更加有趣的应用或者得到更好的用户体验.集体智慧是指在大量的人群的行为和数据中收集答案,帮助你对整个人群得到统计意义上的结论,这些结论是我们在单个个体上无法得到的,它往往是某种趋势或者人群

[Recommendation System] 推荐系统之协同过滤(CF)算法详解和实现

1 集体智慧和协同过滤 1.1 什么是集体智慧(社会计算)? 集体智慧 (Collective Intelligence) 并不是 Web2.0 时代特有的,只是在 Web2.0 时代,大家在 Web 应用中利用集体智慧构建更加有趣的应用或者得到更好的用户体验.集体智慧是指在大量的人群的行为和数据中收集答案,帮助你对整个人群得到统计意义上的结论,这些结论是我们在单个个体上无法得到的,它往往是某种趋势或者人群中共性的部分. Wikipedia 和 Google 是两个典型的利用集体智慧的 Web