Codeforces Education round17

博客内容介绍了Codeforces教育赛17中的两道题目。第一题要求找出一个数字n的第k大的因子,通过枚举到平方根并排序解决。第二题涉及如何在限制条件下为不同接口的电脑购买最经济的鼠标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这几天过年没怎么写题(说的好像没过年就在写题一样),把最近的比赛补一补吧

cf762A  

题意大概是给一个数字n,让我们求这个数字的因子并且从小到大排序后,求第k大的因子,如果不存在在输出-1

n<= 1e15 k<=1e9

这个数字看上去很吓人,但是仔细想一下,由于因子是成对出现的,我们只要枚举到sqrt(n)就能知道这个数字有多少因子,然后丢到一个集合里排序后输出即可,而且即使是1e15也没有1e7的因子。所以直接写就可以了。

#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<time.h>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<iostream>
using namespace std;
#define  LONG long long
const int   INF=0x3f3f3f3f;
const int MOD=1e9+7;
const double PI=acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
LONG num[100000];
int main()
{
    LONG n , k;
    cin>>n>>k;
    int tot = 0;
    for(LONG i = 1 ; i* i <= n ;++ i)
    {
        if( i * i == n ) {num[ ++tot ] = i;break ;}
        if(n % i == 0)
        {
            num[++ tot  ] = n/i;
            num[++ tot ] = i;
        }
    }
    sort( num + 1 , num + tot + 1);
    if( k > tot )cout<<-1 <<endl;
    else cout<<num[k]<<endl;
}
cf 762B

 大概意思就是需要购进一批鼠标,有两种接口,现在实验室有只能插A接口的电脑a台,只能插B接口的电脑b台,两个接口都有的电脑c台,问我们在优先使得购进尽量多且合适的鼠标的前提下,最小的价格是多少
这道题我也不太能证明,就是先把鼠标按价格排序后,优先满足单一接口的电脑,然后剩下的给两个接口的电脑。过程比较简便。

#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<time.h>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<iostream>
using namespace std;
#define  LONG long long
const int   INF=0x3f3f3f3f;
const int MOD=1e9+7;
const double PI=acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
struct Mouse
{
    int v ;
    char name[50];
}mouse[3500000];
bool cmp( Mouse a , Mouse b)
{
    return a.v < b.v;
}
int main()
{
    int a , b , c;
    scanf("%d%d%d",&a,&b,&c);
    int m ;
    cin>>m;
    for(int i = 1; i <=m ;++i)
        scanf("%d",&mouse[i].v),
        scanf("%s",mouse[i].name);
    sort( mouse +1 , mouse + m +1 , cmp );
    int tot = 0 ;
    LONG sum_mon = 0;
    for(int i =1 ;i <= m ;++ i)
    {
        if(mouse[i].name[0] == 'U')
        {
            if(a > 0)
                a--;
            else if( c > 0)
                c -- ;
            else continue ;
            tot ++ ;
            sum_mon += (LONG )mouse[i].v;
        }
        else
        {
            if(b > 0)
                b-- ;
            else if ( c > 0)
                c -- ;
            else continue ;
            tot ++ ;
            sum_mon += (LONG)mouse[i].v;
        }
    }
    printf("%d %lld\n",tot , sum_mon);
}
cf 763C  (双指针)
这道题我一开始读错了题意,后来看题解,又把把样例仔细看过才搞懂
题意大概就是给两个字符串,然后让我们把第二串去掉中间连续部分,使得剩下的前缀和后缀连起来是第一个串的子串,(这里子串含义类似于LCS,对于第一个串不需要连续,第二个串需要连续。) 并要求中间去掉部分最短,输出剩下的前后缀连起来的子串,如果不存在这个子串输出'-' 。两个串的长度均是1e5。
比如ABCBA    ABDEBA ,那么去掉中间连续部分DE,然后得到ABBA,ABBA是ABCBA的子串,且DE是满足条件的最短去掉的部分。
仔细分析一下,大概就是跟双指针有关的。由于这个子串是第二个串的前缀连上后缀(也有可能只是的后缀或者前缀),我们存一下第二个串的前缀每个字符到达第一个串的位置,
比如DABCBAE ABDEBA 得到2 3 -1  -1  -1  -1 (-1的意思就是这个字符匹配不上了,实际上为了方便可以把数组预设为INF,然后大于第一个串长度的都视为匹配不上)
同样的方式我们处理一下后缀部分,然后我们得到了两个数组
比如abacaba   abcdcba,得到1 2 4 -1 -1 -1 -1 和 -1 -1 -1 -1 4 6 7
我们现在要做的就是找到一对(i,j),j > i且bj > ai,同时j-i最小。 指针p1初始指向第一个数组的最后一个合法元素(合法元素指这里的字符能匹配的上,不是-1或者INF)指针p2初始指向第二个数组最后一个元素再往后移动一位的位置。
然后p2每次向前移动一位,如果p2<=p1或者b[p2]<=a[p1],p1向前移动一位,然后每次维护一下p2 - p1的min值。注意一下有可能只去掉前缀或者只去掉后缀,边界问题处理一下

#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<time.h>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<iostream>
using namespace std;
#define  LONG long long
const int   INF=0x3f3f3f3f;
const int MOD=1e9+7;
const double PI=acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
int num [30][100100];
char str1[100100];
char str2[100100];
int a[100100];
int b[100100] ;
int main()
{
    clr1( a );
    clrI( b ) ;
    scanf("%s%s",str1 , str2 );
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    int j,i;
    j = 0;
    for( i = 0 ; i < len2 ;++ i)
    {
        while(str1[j] != str2[i] && j < len1) ++ j;
        if( j >= len1)break ;
        a[i] = j ;
        j++;
    }
    int p1 = i - 1;
    j = len1 - 1;
    for( i = len2 - 1 ; i >= 0 ; -- i)
    {
        while ( str1[j] != str2[i] && j >= 0) -- j;
        if(j < 0 )break ;
        b[i] = j;
        -- j;
    }
    int p2;
    if(b[len2 - 1] > a[p1]) p2 = len2 - 1;
    else p2 = len2 ;
    int res = p2 - p1;
    for( i = p1 , j = p2 ; ; )
    {
        if(  j < 0  || b[j] == -1&& j < len2)break ;
        if(i >= 0)
        if(a[i] >= b[j]|| j <= i)
        {
            -- i;
        }
        if(res > j - i)
        {
            res = j - i;
            p1 = i , p2 =  j;
        }
        j -- ;
    }
    if(p1 < 0 && p2 >= len2)cout<<'-'<<endl;
    else{
        if( p1 == p2 ) p2 ++ ;
        for( i = 0 ; i <= p1 ; ++ i)printf("%c",str2[i]);
        for( i = p2 ; i <= len2 -1 ; ++ i) printf("%c",str2[i]);}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值