Educational Codeforces Round 92 (Rated for Div. 2) (A-E)

题目:A. LCM Problem
题意:给定l和r,找到一对x,y,LCM(x,y)属于[l,r]。

设gcd,最小的x为l,可知最优的y为2*l。

#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=1e9+7;
const int MAXlen=2e4+10;
const int MAX=2e5+10;
double eps=1e-4;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int l,r;
        scanf("%d %d",&l,&r);
        if(2*l>r)
        {
            printf("-1 -1\n");
            continue;
        }
        printf("%d %d\n",l,2*l);
    }
    return 0;
}

题目:B. Array Walk
题意:给定n,k,z,长度为n的数组,k为你移动的总次数,z是你向左移动的次数。每次你可以选择向左还是向右移动,从a[i]到a[i-1],总价值+a[i-1]同理向右移动。在一个点不能连续向左移动2次及两次以上。问价值最大的。

在这里插入图片描述

每次自己写的dp状态定的偏点转移方程就很麻烦,还是需要改进。
z的值不大可以作为dp状态量,dp[i][j]:在第i个变量已经向左移动了j次的最大价值。

#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=1e9+7;
const int MAXlen=2e4+10;
const int MAX=2e5+10;
double eps=1e-4;
ll a[100010];
ll dp[100010][10];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ll n,k,z;
        ll i,j;
        scanf("%lld %lld %lld",&n,&k,&z);
        for(i=1;i<=n;i++)
        {
            for(j=0;j<7;j++)
                dp[i][j]=0;
            scanf("%lld",&a[i]);
        }
        ll ans=0;
        dp[1][0]=a[1];
        for(i=2;i<=n;i++)
        {
            for(j=0;j<=z;j++)
            {
                dp[i][j]=max(dp[i-1][j]+a[i],dp[i][j]);//没有向左移动
                if(i-1+2*j<=k)
                    ans=max(ans,dp[i][j]);
                dp[i-1][j+1]=max(dp[i-1][j+1],dp[i][j]+a[i-1]);//向左移动
                if(i-2+2*(j+1)<=k&&(j+1<=z))//确保在k次之内,向左移动次数不大于z
                ans=max(ans,dp[i-1][j+1]);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

题目:C. Good String
题意:在这里插入图片描述
初始:1 2 3 4 5 6->2 3 4 5 6 1要等于6 1 2 3 4 5
2=6=4,1=3=5。奇数时全部相等。

只有这两种情况。

#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=1e9+7;
const int MAXlen=2e4+10;
const int MAX=2e5+10;
double eps=1e-4;
char s[200010];
int book[12];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(book,0,sizeof(book));
        scanf("%s",s);
        int n,i,j;
        n=strlen(s);
        int ans=n-2;
        for(i=0;i<n;i++)
            book[s[i]-'0']++;
        for(i=0;i<=9;i++)
            ans=min(ans,n-book[i]);
        for(i=0;i<=9;i++)
        {
            if(!book[i])
                continue;
            for(j=0;j<=9;j++)
            {
                if(!book[j]||i==j)
                    continue;
                bool gg=true;
                int sum=0;
                for(int k=0;k<n;k++)
                {
                    if(gg){
                        if(s[k]-'0'==i)
                        {
                            gg=false;
                            sum++;
                        }
                    }
                    else{
                        if(s[k]-'0'==j)
                        {
                            gg=true;
                            sum++;
                        }
                    }
                }
                if(sum&1)
                    sum--;
                ans=min(ans,n-sum);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

题目:D. Segment Intersections
题意:初始化有两个区间[l1,r1],[l2,r2],有n个这两个区间,每次你可以给第i个区间左端点-1,或者右端点+1,如果两个区间的重叠部分时[x,y]则价值为y-x。最小操作几次使得价值为k。

可以确定,先尽量把第i个区间相互完善到,max(r2,r1)-min(l1,l2),再去判断一下完成后,补充2个操作换一个的价值记录下来。之后就是分情况讨论,两个区间开始就没有重叠部分的价值,以及完全重合,部分重合的情况,我写的过于繁杂可以忽略。代码丑的一

#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=1e9+7;
const int MAXlen=2e4+10;
const int MAX=2e5+10;
double eps=1e-4;
ll dp[200100];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        ll n,i,j,k;
        scanf("%lld %lld",&n,&k);
        for(i=0;i<=n;i++)
            dp[i]=llinf;
        ll l1,r1,l2,r2;
        ll ans=0;
        scanf("%lld %lld",&l1,&r1);
        scanf("%lld %lld",&l2,&r2);
        if(l1>l2){
            swap(l1,l2);
            swap(r1,r2);
        }
        if(r1<=l2){
            ll sum=0;
            ll rmax=r2-l1,rcha=l2-r1;
            for(i=1;i<=n;i++){
                if(sum+rmax<=k){
                    sum+=rmax;
                    ans+=rcha+rmax;
                        if(k-sum>=0)
                    dp[i]=ans+2*(k-sum);
                }
                else{
                    ans+=rcha+(k-sum);
                    sum=k;
                    break;
                }
            }
            if(sum<k){
                ans+=(k-sum)*2;
            }
            for(i=1;i<=n;i++)
                ans=min(ans,dp[i]);
            printf("%lld\n",ans);
        }
        else if(r2>r1){
            ll sum=(r1-l2)*n;
            ll rmax=l2-l1+r2-r1;
            if(sum>=k)
            {
                printf("0\n");
                continue;
            }
            for(i=1;i<=n;i++)
            {
                if(sum+rmax<=k)
                {
                    ans+=rmax;
                    sum+=rmax;
                        if(k-sum>=0)
                    dp[i]=ans+(k-sum)*2;
                }
                else{
                    ans+=(k-sum);
                    sum=k;
                    break;
                }
            }
            if(sum<k){
                ans+=(k-sum)*2;
            }
            for(i=1;i<=n;i++)
                ans=min(ans,dp[i]);
            printf("%lld\n",ans);
        }
        else {
            ll rmax=l2-l1+r1-r2;
            ll sum=(r2-l2)*n;
            if(sum>=k)
            {
                printf("0\n");
                continue;
            }
            for(i=1;i<=n;i++){
                if(sum+rmax<=k)
                {
                    sum+=rmax;
                    ans+=rmax;
                    if(k-sum>=0)
                    dp[i]=ans+(k-sum)*2;
                }
                else
                {
                    ans+=(k-sum);
                    sum=k;
                    break;
                }
            }
            if(sum<k){
                ans+=(k-sum)*2;
            }
            for(i=1;i<=n;i++)
            ans=min(ans,dp[i]);
            printf("%lld\n",ans);
        }
    }
    return 0;
}

题目:E. Calendar Ambiguity
题意:给定一年m个月,一个月d天,一周w天,问x月y日的星期等于y月x日的星期的一对(x,y)的对数。
计算日期星期是: ( ( x 1 ) d + y ) m o d    w + 1 = ( ( y 1 ) d + x ) m o d    w + 1 ((x-1)*d+y) \mod w+1 = ((y-1)*d+x)\mod w+1
得到 ( y x ) ( d 1 ) = k w , k > = 1 (y-x)*(d-1) = k*w,k>=1且是整数
y,x属于min(d,m),如果日期大,就没有这个月份。
y>x,x=1时y-x为[1,m-1],但是我们还需要判断(d-1)与w是否存在倍数关系,所以继续gcd(d-1,w)同除,(d-1)与w互质,只需要考虑(y-x)与w的关系了,w=/gcd,(d-1)=/gcd,值就是 m 1 w \frac{m-1}{w} 。同理x=2,3…。 i = w m 1 i w \sum_{i=w}^{m-1} \frac{i}{w}
随意带一个值观察可发现规律。

#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=1e9+7;
const int MAXlen=2e4+10;
const int MAX=2e5+10;
double eps=1e-4;
ll dp[200100];
ll gcd(ll a,ll b)
{
    if(!b)
        return a ;
    else{
        return gcd(b,a%b);
    }
}
int main()
{
    for(int i=1;i<=14;i++)
    {
       // printf("%d ",i/5);
    }
    int T;
    scanf("%d",&T);
    while(T--){
        ll m,d,w;
        scanf("%lld %lld %lld",&m,&d,&w);
        ll g=gcd(d-1,w);
        w/=g;
        m=min(m,d)-1;
        ll n=(m/w)-1;
        ll ans=n*(n+1)/2*w;
        ans+=(m%w+1)*(m/w);
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43958964/article/details/107748484