codeforces暑假集训第二周总结


#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;
int t,k,n,x,cnt;

int main(){

    cin >> t;
    while(t--){
        
        cnt = 1;
        cin >> n >> k;
        vector < pair <int,int> > v(n);

        for(int i = 0;i < n;i++) cin >> v[i].first,v[i].second = i;
        sort(v.begin(),v.end());

        for(int i = 0;i < n - 1;i++) 
            if(v[i].second + 1 != v[i + 1].second) 
                cnt++;

        if(cnt <= k) cout << "YES\n";
        else cout << "NO\n";
    }

    return 0;
}

这个题一开始想的太简单了,只考虑到了位置不对的数组,但是如果像1 4 2这样的,位置不对的只有两个,但是必须需要分成三组才能从小到大 1 4 和2 1 和2 4都不行 因为1就插不到里面去。所以我们需要将每个数的位置记一下,然后按从小到大进行一个排序,排序之后一个个对比,如果前一个数没有和后一个数在之前的序列中是连续的,那么这两个就必须要分开,这是为了给中间留个位置 比如1 2 7 5 不能把1 2 7分成一组,这样5就进不来了。只要最后分的次数小于等于k了,那么就输出yes。

#include<bits/stdc++.h>
using namespace std;

const int maxn = 2e4 + 10;
int n,cnt,arr[maxn],pos;

int main(){

   cin >> n;
   for(int i = 0;i < n;i++){
       cin >> arr[i];
       if((int)abs(arr[i]) % 2 == 1) cnt++;
   }
   pos = 1;
   for(int i = 0;i < n;i++){
       if(arr[i] % 2 == 0) cout << arr[i] / 2 <<'\n';
       else{
           if(pos++ <= cnt / 2) cout << (int)floor(arr[i] * 1.0 / 2) <<'\n';
           else cout << (int)ceil(arr[i] * 1.0 / 2) << '\n';
       }
   }

   return 0;
}

b i b_i bi = a i 2 \frac{a_i}2 2ai + x
因为 ∑ i    =    1 n b i \sum_{i\;=\;1}^nb_i i=1nbi = 0, ∑ i    =    1 n a i \sum_{i\;=\;1}^na_i i=1nai = 0 x的取值只能为 1 2 \frac1 2 21 − 1 2 -\frac1 2 21 所以所有的x的和要为0,即一半为正的一半为负的,即有一半奇数要向上取整,有一半奇数要向下取整

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;
int n,a[maxn],b[maxn],pos[maxn],c[maxn],ans,Max;

int main(){

   cin >> n;
   for(int i = 1;i <= n;i++) cin >> a[i];
   for(int i = 1;i <= n;i++) cin >> b[i];
   for(int i = 1;i <= n;i++) pos[b[i]] = i;
   for(int i = 1;i <= n;i++) c[i] = pos[a[i]];

   ans = 0,Max = -1;
   for(int i = 1;i <= n;i++){
       if(c[i] > Max) Max = c[i];
       else ans++;
   }
   cout << ans << '\n';
   return 0;
}

我们知道了一开始的序列和最后的序列,我们需要找到每一辆车他所移动之后的位置,比如3 5 1 2 4 变成了 4 3 1 5 2 车3从最开始的位置变到了第二个位置 它所在的位置就为2,所以就能得到这么一个序列2 4 3 5 1,指的是每辆车变化之后的位置。为什么要这样一个序列呢,首先3车是最先进去的,而出来后却不在第一个位置而是在第二个位置,所以如果要是它后面的车进去出来之后却在它的位置前面,说明这辆车超车了。车3 5的位置变成了2 4是正常的,因为车5并没有超过车3,而这个时候第三个进去的车1的位置却到了第二个进去的车5的前面去了,说明它超车了,这个第四个进去的车2变到了第五个位置,没有超过前面的车5是对的,但第五个位置已经是最后了,在车2后面的车4必定超车了。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
int n,m;
const int mod = 1e9 + 7;

ll power(ll a,ll b){
   a %= mod;
   ll res = 1;
   while(b > 0){
       if(b & 1) res *=a % mod;
       a *= a % mod;
       b >>= 1;
   }
   return res;
}

int main(){

   cin >> n >> m;
   cout << power(power(2,m) - 1,n);

   return 0;
}

以后所有用次方的地方都要自己写一个快速幂出来,不然就会超时。快速幂一个礼物三个盒子的可以放1 放2 放3 放1 2 放1 3 放2 3 放1 2 3但是不能不放,也就是3的真子集去掉了空集, 2 m − 1 {2^m} - 1 2m1种情况,而第二件礼物和第一件礼物完全不冲突,也有 2 m − 1 {2^m} - 1 2m1种情况,所以n个礼物就有 ( 2 m − 1 ) n ({2^m} - 1)^n (2m1)n种情况。快速幂背一下板子就好了,记住用法快速打出来

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
ll odd,eve,n,m,t,x,ans;

int main(){

    cin >> t;
    while(t--){

        cin >> n;
        odd = eve = ans = 0;

        for(int i = 0;i < n;i++){
            cin >> x;
            if(x % 2 == 0) eve++;
            else odd++;
        }

        cin >> m;
        for(int i = 0;i < m;i++){
            cin >> x;
            if(x % 2 == 0) ans += eve;
            else ans += odd;
        }

        cout << ans << '\n';
    }
}

这个题很简单,并不需要每一个相减那样会超时的,只需要找一下偶数和奇数截距就好,写到博客里并不是写思路,一定要一定要看清楚数据范围,又忘记开longlong了,一交就wa

#include<bits/stdc++.h>
using namespace std;

string s;
int t,n,odd,eve,bad,odds,eves;

int main(){

    cin >> t;
    while(t--){
        
        odd = eve = bad = 0;
        cin >> n;
        for(int i = 0;i < n;i++){
            cin >> s;odds = eves = 0;
            int len = (int)s.size();
            if(len % 2 == 1) odd++;
            else{
                eve++;
                for(int j = 0;j < len;j++){
                    if(s[j] == '1') odds++;
                    else eves++;
                }
                //cout << odds << ' ' << eves << '\n';
                if(odds % 2 == 1 || eves % 2 == 1) bad++;
               // cout << bad << '\n';
            }

        }
        if(bad % 2 == 1 && odd == 0) cout << n - 1 << '\n';
        else cout << n << '\n';
        
    }
    return 0;
}

如果是长度为奇数的串的话,那么不管有几个0和几个1都能重新排列成回文串,如果长度为偶数的话,就要分为两种情况,如果1和0的个数为偶数的话,那么就可以重新排列成回文串。但如果为奇数的话,那么就不可以,这个时候就需要找其他的串就交换1和0了。首先就是找长度为奇数的串,因为长度为奇数的串不管交换掉其中的哪一个也仍为回文串,这时候就可以将坏串中的奇数个数的0或1转换成1或0变成偶数了。或者两个坏串之间相互交换,因为他们都是奇数个数的0和1,相加后都是偶数个数的0和1这个时候重新分配后就可以变成回文串了。所以如果没有奇数串但又有奇数个数的坏串的时候,就会有n-1个回文串,其他情况均为n个回文串


#include<bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;
map <int,int> m;
vector <int> v;
int t,n,k,d,minn,cnt;

int main(){

   cin >> t;
   while(t--){

       minn = INF;cnt = 0;
       m.clear(),v.clear();
       cin >> n >> k >> d;
       for(int i = 0;i < n;i++){
           cin >> k;
           v.push_back(k);
       }

       for(int i = 0;i < d;i++){
           if(!m[v[i]]) cnt++;
           m[v[i]]++;
       }
       minn = cnt;

       for(int i = d;i < n;i++){
           m[v[i - d]]--;
           if(!m[v[i - d]]) cnt--;
           if(!m[v[i]]) cnt++;
           m[v[i]]++;
          // cout << cnt << " " << minn << '\n';
           if(cnt < minn) minn = cnt;
       }

       cout << minn << '\n';
   }
}

数据范围比较大,不能通过暴力的去解。我们首先用一个vector来存数据,这样比较节省空间,虽然有k个节目,但是真正能用到的可能没有k个,所以也是为了节省空间我开了map。一开始我们将前d天的节目存下来,如果存之前这个m为0了,就让cnt++意思是这d天内有一个新节目。之后从第d+1天开始,每天减去d天前的一个节目,如果减去这个节目后m为0了,就说明这d天之内都没有这个节目了。再加上第d+1天的节目。每次用cnt和minn比较,找到所有区间里面cnt最小的一个。

#include<bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;
int t,n,x,minn,cnt;

void no(){
   cout << -1 << '\n';
}

int main(){

   cin >> t;
   while(t--){

       cin >> n;
       vector < vector < int > > v(n, vector < int > ());
       minn = INF;
       
       for(int i = 0;i < n;i++){
           cin >> x;v[x - 1].push_back(i);
       }
       
       if(n == 1){
           no();
           continue;
       }

       for(int i = 0;i < n;i++){
           
           if(v[i].empty()) continue;
           for(int j = 0;j < (int)v[i].size() - 1;j++){
               cnt = v[i][j + 1] - v[i][j] + 1;
               if(cnt < minn) minn = cnt;
           }
       }
       if(minn == INF){
           no();
           continue;
       }
       cout << minn << '\n';
   }
   return 0;
}

这个题的思路很简单。但是vector的嵌套还是用不熟难受。首先vector的嵌套要写成这样:vector < vector < int > > v(N,vector < int > () ) 里面一定是多一个括号的。其次就是每次要是需要清空vector的话,在v里用clear只能清空vector的大容器,而vector的小容器是没有任何变化的。我们最好是在每次循环的时候重新定义vector,这个题要么用stable_sort排个稳定的序,依次找相同元素的所在位置的最小差,如果minn没有变化说明所有的元素都只出现了1次,输出-1.要么就用vector做,每次将相同元素的位置添加到vector里面,后面遍历一遍vector找最小就好,很简单的一道题主要是卡死在vector上面了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值