codeforces1257

A.

题意:一共n个点,有俩点叫a b,可以进行m次交换操作,问最大ab点相距多少。

水题

#include<iostream>
#include<cmath>
using namespace std;
int min(int a,int b){
	return a<b?a:b;
}
int main(){
	int t;
	int n,m,a,b;
	cin>>t;
	while(t--)
	{
		cin>>n>>m>>a>>b;
        int dis=abs(a-b);
		int ans=min(dis+m,n-1);
		cout<<ans<<endl;
	}

}

B做过了

C.

题意:给n个数,求这之中两个相同的数字最小距离是多少

思路:题意挺简单的,但是理解题意的时候可费劲了,他叙述的跟多复杂一样,什么dominated by,根本就看不懂,明明就是这点事,英语还是要好好学,一开始的做法还挺复杂的,就是想着一点点处理,但是wa了,看不出来哪里错了,然后改了个思路,用一个vis数组表示每个数是否输入过并且表示他最后一次出现的位置,每次输入的时候,如果之前没有输入过,就把vis设为当前的位置,输入过就求距离比较,找到最小的。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
typedef long int ll;

int a[200005],vis[200005];
int main()
{
	int t;
	int n,i,j;
	
	cin>>t;
	while(t--)
	{
        memset(vis,0,sizeof(vis));
		cin>>n;
		int ans=inf;
		int flag=0;
		for(i=1;i<=n;i++)
		{
			cin>>a[i];
			if(vis[a[i]]==0) vis[a[i]]=i;
			else{
			flag=1;
			if(abs(vis[a[i]]-i)<ans) ans=abs(vis[a[i]]-i);
			vis[a[i]]=i;
			}
		}
		if(flag)
		cout<<ans+1<<endl;
        else
	    cout<<-1<<endl;
	}
		 
	return 0;
}

D.

题意:有丶复杂,你有m个英雄,每个英雄有力量值和耐力值,然后按顺序要打n个怪兽,每个怪兽也有力量值,如果英雄的力量值大于等于怪兽就可以干掉他,在一天中会消耗掉他的一个耐力值,问你最少可以用多少天来弄死所有怪兽。

思路:自己想的时候忽略了一个点,就是每个英雄不只可以用一次,因为他在战斗后休息一天,耐力值会回复满,这点错了,导致思路有点乱,按每个英雄处理,看每个英雄应该放在什么地方最好,但是会涉及很多问题,太复杂了。比赛的时候时间也不是很多了就没有继续往下做,看到了别人的题解之后就又懂了。用简单的贪心就能做,用一个数组suf[i]表示,耐力值大于等于i的英雄最大的力量是多少。然后从左向右对怪兽进行直接处理,有了一个suf数组就可以直接处理了,贪心思想就是在每个地方能用的英雄的最大耐力是多少,用一个maxx表示接下来要面对的怪兽力量是多少。这样一看,这思路挺简单的。

#include<iostream>
using namespace std;
const int maxn=2e5+10;
int n,m;
int a[maxn];
int suf[maxn],b[maxn];
int   p[maxn],s[maxn];
int main()
 {
     int t,i,j;
	 cin>>t;
	 while(t--){
	      cin>>n;
     for(i=1;i<=n;i++) b[i]=-1;
     for(i=1;i<=n;i++) cin>>a[i];
	      cin>>m;
		  for(i=1;i<=m;i++) {
			  cin>>s[i]>>p[i];
			  if(b[s[i]]<p[i]) b[s[i]]=p[i];
		  }
		  suf[n+1]=-1;
		  for(i=n;i>0;i--) suf[i]=max(suf[i+1],b[i]);
		  int pis=1,ans=0;
		  while(pis<=n)
		  {
			  int cnt=pis;
			  int maxx=a[pis];
			  while(cnt<=n&&suf[cnt-pis+1]>=maxx){
				  cnt++;
				  maxx=max(maxx,a[cnt]);
			  }
			  if(cnt==pis){ans=-1;break;}
			  ans++;
			  pis=cnt;
		  }
		  cout<<ans<<endl;
	 }

}

E.

题意:三个人,每个人掌握着几个数,三人一共掌握1到n n个数,问你怎样怎样用最小的操作数达到,三人分别掌握1到i,i+1到j,j+1到n几个数。

思路:处理前缀和,用cnt数组分别表示三人前i个数中有几个数,具体的推导还是看的别人作得。

#include <bits/stdc++.h>
 
#define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
#define LL long long
using namespace std;
const int maxn = (ll) 2e5 + 5;
const int mod = 1000000007;
const int inf = 0x3f3f3f3f;
int cnt1[maxn], cnt2[maxn], cnt3[maxn];
int minn[maxn];
vector<int> v1, v2, v3;
 
int main() {
    start;
    int k1, k2, k3;
    cin >> k1 >> k2 >> k3;
    v1.resize(k1 + 5);
    v2.resize(k2 + 5);
    v3.resize(k3 + 5);  
    for (int i = 1; i <= k1; ++i) {
        cin >> v1[i];
        ++cnt1[v1[i]];
    }
    for (int i = 1; i <= k2; ++i) {
        cin >> v2[i];
        ++cnt2[v2[i]];
    }
    for (int i = 1; i <= k3; ++i) {
        cin >> v3[i];
        ++cnt3[v3[i]];
    }
    int n = k1 + k2 + k3;
    for (int i = 1; i <= n; ++i) {
        cnt1[i] = cnt1[i - 1] + cnt1[i];
        cnt2[i] = cnt2[i - 1] + cnt2[i];
        cnt3[i] = cnt3[i - 1] + cnt3[i];
    }
    for (int i = 0; i <= n; ++i)
        minn[i] = cnt3[i] - cnt2[i];
    for (int i = n - 1; i >= 0; --i)
        minn[i] = min(minn[i + 1], minn[i]);
    int ans = inf;
    for (int i = 0; i <= n; ++i) {
        int t = cnt2[i] - cnt1[i] + minn[i] + cnt1[n] + cnt2[n];
        ans = min(ans, t);
    }
    cout << ans;
    return 0;
}

F.

题意:给n个数,每个数给用一个x异或操作,让他们最后得到的二进制数1的个数相同,问这个数是多少。

思路:我见过这题,我记得是c题,当时补题的时候就没看懂,没想到这么快就遇到了,该学的还是要早点学啊,相似度这么高的题都做不出来确实是不应该。

#include <bits/stdc++.h>
#define LL long long
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define dep(i, j, k) for(int i = k; i >= j; i--)
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define mem(i, j) memset(i, j, sizeof(i))
#define pb push_back
using namespace std;
int ans = -1, n;
map < vector< int >, int > mp;
vector< int > Q;
int a[105];
void dfs1(int num, int statu){
    if(num > 15) {
        Q.clear();
        for(int i = 1; i <= n; i++) {
            Q.push_back(__builtin_popcount((statu ^ a[i]) % (1 << 15)));
        }
        for(int i = 1; i < n; i++) {
            Q[i - 1] = Q[i] - Q[i - 1];
        }
        Q.pop_back();
        if(!mp[Q]) mp[Q] = statu;
        return ;
    }
    dfs1(num + 1, statu);
    dfs1(num + 1, statu | (1 << (num - 1)));
}
void dfs2(int num, int statu) {
    if(num > 15) {
        Q.clear();
        for(int i = 1; i <= n; i++){
            ///__builtin_popcount(x) 用于计算x的二进制位上1的个数。
            Q.push_back(__builtin_popcount(statu ^ (a[i] >> 15)));
        }
        for(int i = 1; i < n; i++) {
            Q[i - 1] = -1 * (Q[i] - Q[i - 1]);
        }
        Q.pop_back(); /// 弹出最后一个元素。
        if(mp[Q]) {
            ans = mp[Q] | (statu << 15);
        }
        return ;
    }
    dfs2(num + 1, statu);
    dfs2(num + 1, statu | (1 << (num - 1)));
}
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    dfs1(1, 0); dfs2(1, 0);
    printf("%d\n", ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值