Codeforces 1200-1400

Codeforces 1200-1400

1513B - AND Sequences

题意:t组测试每组测试给定一个长度为n的数组a[ ] 问在全排列的数组中能找出几种使得or all i from 1 to n 使得a1&a2&…&ai=ai+1&ai+2&…&an

思路:将所有的数字与一遍得出x如果存在这样的排列那么至少会存在两个数字等于x (记数组中等于x的数的个数为sum )那么根据组合可得(sum-1)sum(n-2)!

代码如下

#include<iostream>
#define ll long long
using namespace std;

const int N=2e5+10,mod=1e9+7;

ll a[N];

ll fac(ll x)
{
    ll ans=1;
    for(ll i=1;i<=x;i++) ans=ans*i%mod;
    return ans%mod;
}

int main()
{
    int t;cin>>t;
    while(t--)
    {
        ll n;cin>>n;
        for(int i=0;i<n;i++) cin>>a[i];

        ll x=a[0],sum=0;//sum为数组中等于x的个数
        for(int i=1;i<n;i++) x=x&a[i]; //x为全部数字与后的结果

        for(int i=0;i<n;i++)
            if(a[i]==x)
                sum++;
        
        //cout<<sum<<' '<<n<<endl;

        if(sum<2) cout<<0<<endl; //如果sum<2那么不存在排列情况
        else cout<<(sum-1)*sum%mod*fac(n-2)%mod<<endl;
    }
    return 0;
}

1510K - King’s Task

题意:给你一段含全排列n*2的数列 问你在一下两种操作中是否有可能使得他们从小到大有序

1.交换奇数位与后面的偶数位

2.交换第i位和n+i位

思路:题目给了三秒的时间n是2000 所以可以暴力

1.一二两种操作不可能重复操作因为重复操作两次就会复原(懂得都懂)

2.循环运行一二两个操作如果在某次运行后数组回到了一开始的状态那么说明他永远也不可能有序了直接输出-1

3.那么是先运行1操作呢还是先运行2操作呢 我的想法是先交替运行1 2操作当回到一开始的状态时说明是不可能有序的直接输出-1否则说明他肯定是可以有序的。那么我们在交替运行2 1操作 记录下这两种方法的次数比较取小即可

代码如下:

#include<iostream>

using namespace std;

const int N=2e3+10;
int a[N],b[N],c[N];
int n;
int ans1,ans2,ans;
bool flag1,flag2;

bool check(int a[])//判断是否回到了一开始的状态
{
    for(int i=1;i<=2*n;i++)
        if(a[i]!=b[i])
            return false;
    return true;
}

bool check2(int a[])//判断是否已经有序了
{
    for(int i=1;i<=2*n;i++)
        if(a[i]!=i)
            return false;
    return true;
}

void operate1(int a[])//操作一
{
    for(int i=1;i<2*n;i+=2) swap(a[i],a[i+1]);
}

void operate2(int a[])//操作二
{
    for(int i=1;i<=n;i++) swap(a[i],a[i+n]);
}

int main()
{
    cin>>n;
    for(int i=1;i<=2*n;i++)
    {
        cin>>a[i];
        b[i]=a[i];
        c[i]=a[i];
    }
    if(check2(a))//如果已经有序了直接输出0
    {
        cout<<0<<endl;
        return 0;
    }
    while(1)// 1 2操作
    {
        operate1(a);
        ans1++;
        if(check(a))
        {
            flag1=true;
            break;
        }
        if(check2(a)) break;

        operate2(a);
        ans1++;
        if(check(a))
        {
            flag1=true;
            break;
        }
        if(check2(a)) break;
    }
    if(flag1)
    {
        cout<<-1<<endl;
        return 0;
    }
    while(1) //2 1 操作
    {
        operate2(c);
        ans2++;
        if(check(c))
        {
            flag2=true;
            break;
        }
        if(check2(c)) break;

        operate1(c);
        ans2++;
        if(check(c))
        {
            flag2=true;
            break;
        }
        if(check2(c)) break;
    }

    //cout<<ans1<<' '<<ans2<<endl;

    ans=min(ans1,ans2);// 两种方法取小
    cout<<ans<<endl;
    return 0;
}

D - Epic Transformation

题意:给定一个数列每次取两个不相同的数字删除 问你最后最小的数组长度是多少

思路:先将数组从小到大排列 然后双指针 i指向数组中间 j指向数组的最后位置 如果指向的两个数字相同那么i向前移否则i与j都向前移 当i<0||j<数组中间位置时推出 结果就是数组的长度减去i与j都向前移的情况

代码如下:

#include<iostream>
#include<algorithm>

using namespace std;

const int N=2e5+10;
int a[N];

int n;

int main()
{
	int t;cin>>t;
	while(t--)
	{
		int ans=0;
		cin>>n;
		for(int i=0;i<n;i++) cin>>a[i];
		sort(a,a+n);
		
		int i,j;
		if(n%2)  i=n/2,j=n-1;
		else  i=n/2-1,j=n-1;
		int x=i;
		while(i>=0&&j>x)
		{
			if(a[i]==a[j])
				i--;
			else
			{
				ans++;
				i--;
				j--;
			}
		}
		cout<<n-ans*2<<endl;
	}
	return 0;
}

C - Fibonacci Words(愚人节)

题意:斐波那契字符 与菲波那切数列差不多 问你这串字符串符不符合斐波那契

思路:将A-Z分别映射成0-25 就是玩

代码如下:

#include<iostream>

using namespace std;

int a[100];
string s;

int main()
{
	cin>>s;
	for(int i=0;i<s.size();i++) a[i]=s[i]-'A';
	
	if(s.size()<=2)
	{
		cout<<"YES"<<endl;
		return 0;
	}
	for(int i=2;i<s.size();i++)
		if(a[i]!=(a[i-1]+a[i-2])%26)
		{
			//cout<<a[i]+'A'<<endl;
			cout<<"NO"<<endl;
			return 0;
		}
	cout<<"YES"<<endl;
	return 0;
}

1498B - Box Fitting

题意:给了n个知道长度和高度都为一的矩形和一个高度无限和已知长度为m的容器 把这些矩形全部装进这个容器中能装的最小高度是多少

思路:从大到小排序一遍 然后开一个优先队列 如果当前矩形的长度能放进队列中的话放进去 否则新开一个队列放进去 就是玩

代码如下:

#include<iostream>
#include<queue>
#include<algorithm>

using namespace std;
const int N=1e5+10;
int a[N];

bool cmp(int a,int b)
{
    return a>b;
}

int main()
{
    int t;cin>>t;
    while(t--)
    {
        priority_queue<int> p;
        int ans=0;
        int n,m;cin>>n>>m;
        for(int i=0;i<n;i++) cin>>a[i];
        sort(a,a+n,cmp);
        p.push(0);
        for(int i=0;i<n;i++)
        {
            int l=p.top();
            p.pop();
            if(a[i]<=l) p.push(l-a[i]);
            else
            {
                ans++;
                p.push(l);
                p.push(m-a[i]);
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

1495A - Diamond Miner

题意:给你n个x轴上的点和n个y轴上的点问你他们两两配对组成的三角形的斜边最小和是多少

思路:可以证明 每次都选最小的点构成斜边这样的做法是最优的(数学可证明 三角形斜边之和小于其他两边之和) 就是玩

tips:这道题会卡输入 建议用scanf或者关闭输入输出同步

代码如下:

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

const int N=1e5+10;
double a[N],b[N];

double xx(double a,double b)
{
    return sqrt(pow(a,2)+pow(b,2));
}

int main()
{
    double sum=0;
    int t;cin>>t;
    while(t--)
    {
        double sum=0.0;
        int g=0,h=0;
        int n;cin>>n;
        for(int i=0;i<2*n;i++)
        {
            double x,y;scanf("%lf%lf",&x,&y);
            if(x==0) b[h++]=abs(y);
            else a[g++]=abs(x);
        }
        sort(a,a+g);
        sort(b,b+h);
        for(int i=0;i<n;i++) sum+=xx(a[i],b[i]);
        printf("%.12lf\n",sum);
    }
    return 0;
}

1511B - GCD Length(1100)

题意:给定a b c找出长度为a和b的数字使他们的最大公约数是c长度的数字

思路:如果c=min(a,b)那么就搞成1ea 1eb 否则的话就搞成1ea (b-c)个9*1ec 就是玩

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

void solve()
{
    int a,b,c;
    cin>>a>>b>>c;
    if(c==min(a,b))
    {
        string s1="1",s2="1";
        for(int i=1;i<a;i++)
            s1+="0";
        for(int i=1;i<b;i++)
            s2+="0";
        cout<<s1<<' '<<s2<<endl;
    }
    else
    {
        string s1="1",s2="";
        for(int i=1;i<a;i++)
            s1+="0";
        for(int i=0;i<b-c+1;i++)
            s2+="9";
        for(int i=0;i<c-1;i++)
            s2+="0";
        cout<<s1<<' '<<s2<<endl;
    }
}

int main()
{
    int t;cin>>t;
    while(t--)
        solve();
    return 0;
}

1494B - Berland Crossword

题意:给你一个n*n的二维格子在给定四条边上要放的小格子的数量 问你有没有可能将他给的小格子放进这个二维的格子里

思路:既然他问有没有可能那么我们就要采取最优的方法 二维格子的四个角是我们优先考虑的因为一个角我们可以去掉两个小格子 然后我们就依次遍历四个角最后每条边剩下的格子如果全部都小于等于n-2的话那么就是可行的(需要注意的是依次遍历的顺序是一定的 但是从哪个开始是不一定的所以每种情况都要遍历 如果有一种成功那么就是可行的)

代码如下:

#include<iostream>

using namespace std;
int n;

bool check(int a,int b,int c,int d)
{
    if(a&&b) a--,b--;
    if(b&&c) b--,c--;
    if(c&&d) c--,d--;
    if(a&&d) a--,d--;
    if(a<=n-2&&b<=n-2&&c<=n-2&&d<=n-2) return true;
    return false;
}

int main()
{
    int t;cin>>t;
    while(t--)
    {
        int a,b,c,d;
        cin>>n>>a>>b>>c>>d;
        if(check(a,b,c,d)||check(b,c,d,a)||check(c,d,a,b)||check(d,a,b,c)) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

1493B - Planet Lapituletti

题意:给你一个时间进制和一个时间要求输出离这个事件最近的镜像时间(纯模拟) 需要注意的是你的镜像时间不能超过给的时间进制

思路:没啥思路模拟呗

代码如下:

#include<bits/stdc++.h>
#define endl '\n'
#define null NULL
#define ll long long
#define int long long
#define pii pair<int, int>
#define lowbit(x) (x &(-x))
#define ls(x) x<<1
#define rs(x) (x<<1+1)
#define me(ar) memset(ar, 0, sizeof ar)
#define mem(ar,num) memset(ar, num, sizeof ar)
#define rp(i, n) for(int i = 0, i < n; i ++)
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define pre(i, n, a) for(int i = n; i >= a; i --)
#define IOS ios::sync_with_stdio(0); cin.tie(0);cout.tie(0);
const int way[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
using namespace std;
const int  inf = 0x3f3f3f3f;
const double PI = acos(-1.0);
const double eps = 1e-6;
const ll   mod = 1e9+7;
const int  N = 2e5 + 5;
 
inline void read(int &x){
    char t=getchar();
    while(!isdigit(t)) t=getchar();
    for(x=t^48,t=getchar();isdigit(t);t=getchar()) x=x*10+(t^48);
}
 
int t, h, m, x, y;
 
bool ok(int x){
    if(x<10){
        if(x==0||x==1||x==2||x==5||x==8) return 1;
        else return 0;
    }
    else if(x==100) return 1;
    else{
        int a = x/10, b = x%10, flag = 0;
        if(a==0||a==1||a==2||a==5||a==8) flag = 1;
        if((b==0||b==1||b==2||b==5||b==8)&&flag) return 1;
        else return 0;
    }
}
 
int fi(int x){
    if(x==0||x==1||x==8) return x; //得到对应数字
    if(x==2) return 5;
    if(x==5) return 2;
}
 
bool check(int a, int b){
 
    if(!ok(a)||!ok(b)) return 0; //如果不可翻转
    int flag = 0;
    if(b==100) x = 1;
    else x = fi(b%10)*10+fi(b/10);
    if(a==100) y = 1;
    else y = fi(a%10)*10+fi(a/10);
//    cout << "a: " << a << " b: " << b << endl;
//    cout << "x: " << x << " y: " << y << endl;
    if(x<h&&y<m){
        if(a<10) cout << 0 << a << ":";
        else cout << a%h << ":";
        if(b<10) cout << 0 << b <<endl;
        else cout << b%m << endl;
        return 1;
    }
    return 0;
}
 
signed main()
{
    IOS;
 
    cin >> t;
    while(t --){
        cin >> h >> m;
        int a, b; char c;
        cin >> a >> c >> b;
        for(; ; b ++){
            if(b&&b%m==0) a ++;
//            cout << "check: " << check(a%h, b%m) << endl;
            if(check(a%h, b%m)) break;
        }
    }
 
    return 0;
}

1491B - Minimal Cost

题意:二维矩阵中每行都放一个障碍物 障碍物上下移动花费u元左右移动花费v元 问到达二维矩阵的右下角最少需要花费多少钱

思路:我们可以把障碍物的情况分为三种 1.障碍物没有构成一道墙我们可以直接过去不需要花钱 2.障碍物构成了一道不完美的墙花费u和v的最小值就可以过去 3.障碍物构成了一道竖立的墙这时我们就要先把某个障碍物向右移动在向右或上下移动 花费最小的钱是u+min(v,u)

代码如下:

#include<iostream>
#include<cmath>

using namespace std;
const int N=110;
int a[N];
int n,v,u;

bool check1(int a[])
{
    for(int i=1;i<n;i++)
        if(abs(a[i]-a[i-1])>=2)
            return true;
    return false;
}

bool check2(int a[])
{
    for(int i=1;i<n;i++)
        if(a[i]!=a[i-1])
            return true;
    return false;
}
int main()
{
    int t;cin>>t;
    while(t--)
    {
        cin>>n>>v>>u;
        for(int i=0;i<n;i++) cin>>a[i];
        if(check1(a)) cout<<0<<endl;
        else if(check2(a)) cout<<min(v,u)<<endl;
        else cout<<u+min(v,u)<<endl;        
    }
    return 0;
}

1491B - Minimal Cost

题意:给定了一串数字规定大的或者相等的可以吃掉小的或者相等的然后他可以变强继续吃掉其他人如果他吃掉了其他所有人那么他就是冠军 问你这一串数字里面有多少可以成为冠军的(注意每个数字都很大吃掉其他人的时候要开个 long long)

思路:先排序一下 这个肯定是可以二分的 当小的可以成为冠军那么大的肯定是可以成为冠军的 所以二分去搜索 多的不说了看代码吧

代码如下:

#include<iostream>
#include<algorithm>
#define ll long long

using namespace std;
const int N=2e5+10;
ll a[N],b[N];
bool vis[N];
ll n;
ll sum;

bool check(ll x)
{
    //bool flag=false;
    for(int i=0;i<n;i++)
        if(x>=a[i]&&!vis[i])
            x+=a[i];
    if(x==sum) return true;
    return false;
}

int main()
{
    int t;cin>>t;
    while(t--)
    {
        sum=0;
        cin>>n;
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
            b[i]=a[i];
            sum+=a[i];
        }
        sort(a,a+n);
        ll l=0,r=n-1;
        while(l<r)
        {
            ll mid=l+r>>1;
            vis[mid]=true;
            if(check(a[mid])) r=mid;
            else l=mid+1;
            vis[mid]=false;
        }
        ll x=a[l],ans=0;
        for(int i=0;i<n;i++)
            if(a[i]>=x)
                ans++;
        cout<<ans<<endl;
        for(int i=0;i<n;i++)
            if(b[i]>=x)
                cout<<i+1<<' ';
        cout<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CodeForces - 616D是一个关于找到一个序列最长的第k好子段的起始位置和结束位置的问题。给定一个长度为n的序列和一个k,需要找到一个子段,该子段不超过k个不同的字。题目要求输出这个序列最长的第k好子段的起始位置和终止位置。 解决这个问题的方法有两种。第一种方法是使用尺取算法,通过维护一个滑动窗口来记录\[l,r\]不同的个。每次如果这个小于k,就将r向右移动一位;如果已经大于k,则将l向右移动一位,直到个不大于k。每次更新完r之后,判断r-l+1是否比已有答案更优来更新答案。这种方法的时间复杂度为O(n)。 第二种方法是使用枚举r和双指针的方法。通过维护一个最小的l,满足\[l,r\]最多只有k种。使用一个map来判断的种类。遍历序列,如果当前字在map不存在,则将种类sum加一;如果sum大于k,则将l向右移动一位,直到sum不大于k。每次更新完r之后,判断i-l+1是否大于等于y-x+1来更新答案。这种方法的时间复杂度为O(n)。 以上是两种解决CodeForces - 616D问题的方法。具体的代码实现可以参考引用\[1\]和引用\[2\]的代码。 #### 引用[.reference_title] - *1* [CodeForces 616 D. Longest k-Good Segment(尺取)](https://blog.csdn.net/V5ZSQ/article/details/50750827)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces616 D. Longest k-Good Segment(双指针+map)](https://blog.csdn.net/weixin_44178736/article/details/114328999)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值