第一节课枚举贪心习题(25)

第一节课枚举贪心习题

Flip Game 0星

题意就是问你有没有可能把棋子翻成全黑或全白,翻某个棋子的同时也会让这个棋子的上下左右一起翻。

枚举+贪心
当某一层再怎么翻也不能达到全黑或者全白的时候,只能翻你要翻的棋子的同列的下一行的棋子,所以可以通过二进制枚举第一层可能翻棋子的方案,再通过翻它的下一层把这一层需要翻的棋子翻过去,以此类推一层一层的让他满足全白或者全黑的要求,因为前面的都满足要求了,就看最后一层有没有全白或者全黑,就可以判断方法是否可行。

另开一个数组,用来存这个棋子到底有没有翻,判断一个棋子有没有被翻过去,可以通过判断自身点和其他能影响到这个点是否有没有翻来了判断,点的和取模。

AC代码

#include <iostream>
#include <memory.h>
using namespace std;
int flip[4][4];
char getflip[4][4];
int swapflip[4][4];
int MOVE[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
int sum = 0;
int possible = 0;

bool rightindex(int i,int j){
    return 0<=i && i <4 && 0<=j && j < 4;
}

bool check(int i,int j,int key){
    int i1,j1;
    int num = swapflip[i][j];
    num+=flip[i][j];//要把自己的那个点也要加进去
    for(int w = 0;w < 4;w++){
        i1 = i + MOVE[w][0];
        j1 = j + MOVE[w][1];
        if(rightindex(i1,j1))
            num+=flip[i1][j1];
    }
    if(num%2 == key)
        return true;
    else return false; 
}

void find(int key){

    int sum1,flag;
    for(int n = 0;n <=15;n++){//二进制枚举
        memset(flip,0,sizeof(flip));
        sum1 = 0;
        flag = 1;

        for(int j = 0;j  < 4;j++){
            flip[0][j] = ( n>>(3-j) )&1;
            sum1+=flip[0][j];
        }
      
       

        for(int i = 1;i < 4;i++){
            for(int j = 0;j < 4;j++){
                if(!check(i-1,j,key)){
                    flip[i][j] = 1;//下方要翻牌
                    sum1++;
                }
                    
            }
        }

            for(int j = 0;j < 4;j++){ //判断是否可以全0或1
                if(!check(3,j,key)){
                    flag = 0;
                    break;
                }
            
            }
        
        
        if(flag){
            if(!possible || sum1 < sum)
                sum = sum1; 
            possible = 1;
        }
    }
    return ;
    
}



int main(){
    
    for(int i = 0;i < 4;i++){
        cin >> getflip[i];
       
    }
       
    
    for(int i = 0;i < 4;i++){
        for(int j = 0;j < 4;j++)
            if(getflip[i][j] == 'w')
                swapflip[i][j] = 0;
            else swapflip[i][j] = 1;
    }
    //找黑,找白
    find(1);
    find(0);
    if(!possible)
        cout << "Impossible" << endl;
    else cout << sum << endl;
    //system("pause");
    return 0;
}

Subsequence 0星

尺取

#include <iostream>
using namespace std;
long long num[100010];
long long sum[100010];
int main(){
    long long t,l,r,s,len;
    cin >> t;
    long long ans;
    int flag = 0;
    for(int k = 0;k < t;k++){
        cin >> len >> s;
        for(int i = 1;i <= len;i++){
             cin >> num[i];
             sum[i] = sum[i-1] + num[i];
        }
        flag = 0;
        l = 0;
        r = 1;
        ans = 100010;;
      
        for(;r <= len;){
            if(sum[r]-sum[l]>=s){
                ans = min(ans,r-l);
                l++;
                flag = 1;
            }else r++;
        }
        if(flag)
            cout << ans << endl;
        else cout << 0 << endl;
    }
    //system("pause");
    return 0;
}

Quasi Binary 0星

贪心:拆成的每个数字尽可能的大,把原数的每一位拆分为n个1;最小组成个数是原数中各个位中的最大数

#include <iostream>
using namespace std;
int num[10];

int main(){
    int n;
    cin >> n;
    int len;
    int ans = 0;
    for(int i = 0;;i++){//求最少用几个数组成
        num[i] = n%10;
        ans = max(ans,num[i]);
        n/=10;
        if(!n){
            len = i;
            break;
        }
          
    }
    int flag = 1,flag2;
    cout << ans << endl;
    while(flag){//输出这些数
        flag = 0;
        flag2 = 0;
        for(int i = len;i>=0;i--){
            if(num[i]){
                cout << 1;
                flag2 = 1;
                if(--num[i]>0)
                    flag = 1;
            }else if(flag2)  cout << 0;
           
        }
        cout << " ";
    }
   //system("pause");
    return 0;
}

Protecting the Flowers 1星

贪心:假设序列的前面部分已经按最优解,有两只牛A、B,当AB排序别BA,排序时把AB牛之间的关系求出来,按这个关系sort排序即可,代码中使用的是推出来的除法式子,把除法式子转换为乘法更好。

AC代码

#include <iostream>
#include <algorithm>
using namespace std;
typedef struct Node{
    int ti;
    int di;
    double varth;
}cow;
cow cc[1000000];
int sum[1000000];
bool cmp(cow a,cow b){
    return a.varth < b.varth;
}
int main(){
    int n;
    cin >> n;
    for(int i = 0;i < n;i++){
        cin >> cc[i].ti >> cc[i].di;
        cc[i].varth = (double)cc[i].ti/(double)cc[i].di;
    }
    sort(cc,cc+n,cmp);
    sum[0] = cc[0].ti;
    for(int i = 1;i < n;i++){
        sum[i] = sum[i-1] + cc[i].ti;
    }
    long long cost = 0;
    for(int i = 1;i < n;i++){
        cost+=sum[i-1]*cc[i].di*2;
    }
   
    cout << cost << endl;
    //system("pause");
    return 0;
}

校门外的树 1星

法1开个数组初值赋值为1,把给的区间用memset赋值为0即可,最后扫描数组。

代码略

法2 差分

AC代码

#include<iostream>//差分
using namespace std;
int d[10002];

int main(){
    int L,m;
    int l,r;
    d[0] = 1;
    cin >> L >> m;
    for(int i = 0;i  < m;i++){
        cin >> l >> r;
        d[l] -= 1;
        d[r+1]+= 1;
    }
    int sum = 0;
    if(d[0]>0) sum++;
    for(int i = 1;i <= L;i++){
        d[i] = d[i-1] + d[i];
        if(d[i] > 0)
            sum++;
    }
    cout << sum << endl;
    //system("pause");
    return 0;
}

法3 按每个移走的区间的左端从小到大排序,把重叠区间和并(离散化?) 如果给的初始树的区间很大,差分就不能用了。

AC代码

#include <iostream>
#include <algorithm>
using namespace std;
typedef struct Node{
    int left;
    int right;
}tree;
tree tt[100];

bool cmp(tree a,tree b){
    return a.left < b.left;
}
int main(){
    int L,m;
    cin >> L >> m;
    for(int i = 0;i < m;i++){
        cin >> tt[i].left >> tt[i].right;
        if(tt[i].left >L)
            tt[i].left = L;
        if(tt[i].right > L)
            tt[i].right = L; 
    }

 
    sort(tt,tt+m,cmp);

    int sum = 0,start = 0,end = 0;

    for(int i = 1;i < m;i++){
        
        if(tt[end].right >= tt[i].left){//区间覆盖
            if(i == m-1){//端点
                end = tt[end].right > tt[i].right ? end:i;
                sum += (tt[end].right - tt[start].left+1);
                break;
            }
            end = tt[end].right > tt[i].right ? end:i;
                continue;
        } else{//区间不覆盖
           
            sum+= (tt[end].right - tt[start].left +1);
           start = i;
           end = i;
        }

        if(i == m-1){
            sum += (tt[end].right - tt[start].left+1);
                break;
        }
    }
    cout << L- sum + 1<< endl;
    //system("pause");
    return 0;

明明的随机数 1星

#include <iostream>
#include <cstdbool>
using namespace std;
bool num[1002];
int main(){
    int n;
    cin >> n;
    int x;
    int sum = 0;
    for(int i = 0;i < n;i++){
        cin >> x;
        num[x] = num[x]? true :(sum++,true);
    }
    cout << sum << endl;
    for(int i = 0;i <= 1000;i++)
        if(num[i])
            cout << i << " ";
    //system("pause");  
    return 0;
}

[HNOI2003]激光炸弹 2星

二维差分+枚举 把目标当做点来处理 也就num[i][j]

#include <iostream>
using namespace std;
int num[5010][5010];

int main(){
    int n,r;
    int x,y,v;
    int sum = 0;
    int ans = 0;

    cin >> n >> r;
    for(int i = 0;i < n;i++){
        cin >> x >> y >> v;
        num[x+1][y+1] = v;
    }

    for(int i = 1;i <= 5000;i++)
        for(int j = 1;j <= 5000;j++)
            num[i][j] = num[i][j] + num[i-1][j] + num[i][j-1] -num[i-1][j-1];

    for(int i = 1;i <= 5000;i++){
        for(int j = 1;j <= 5000;j++){
            x = i+r-1 > 5000? 5000: i+r-1;
            y = j+r-1 > 5000? 5000: j+r-1;
            
            sum = num[x][y] - num[i-1][y] - num[x][j-1] + num[i-1][j-1];
            ans = sum > ans ? sum : ans;
            
        }
    }
    cout << ans << endl;
    //system("pause");
    return 0;
}

铺地毯 2星

贪心 对地毯按从大到小判断点是否在地毯上,如果在就是答案

#include <iostream>
using namespace std;
int main(){
    int n;
    int num[10002][4];
    
    cin >> n;
    int x,y;
    for(int i = 1;i <= n;i++)
        cin >> num[i][0] >> num[i][1] >> num[i][2] >> num[i][3];
    cin >> x >> y;
    int flag = 0;
    for(int i = n;i>0;i--){
        if(num[i][2] + num[i][0] >= x && x >=num[i][0])
            if(num[i][3] + num[i][1] >= y && y >=num[i][1]){
                flag = 1;
                cout << i;
                break;
            }
    }
    if(!flag)
        cout << -1;
    return 0;
}

纪念品分组 2星

贪心+双指针
排序后,让价格大的尽可能和多个便宜的合成一组,只考虑便宜的和便宜的不行。比如样例 20 30 50 50 70 80 每组上限100 小的优先为4组,小大结合为3组

代码

#include <iostream>
#include <algorithm>
using namespace std;
int main(){
    int n;
    int sum;
    int num[30010];
    int head,last;
    cin >> sum >> n;
    for(int i = 0;i < n;i++){
        cin >> num[i];
    }
    sort(num,num+n);
    head = 0;
    last = n-1;
    int ans = 0;
    int sum2 = 0;
    while(head <= last){
        sum2 = num[last];
        while(sum2 + num[head] <= sum && head <last){
            sum2+=num[head];
            head++;
        }
        ans++;
        last--;
        
    }
    cout << ans;
    return 0;
}

回文日期 2星

枚举 可以枚举 月和日 得到对应回文,再判断回文是否合法,注意判断二月29闰年

AC代码

#include <iostream>
using namespace std;
int key[8] = {1,10,100,1000,10000,100000,1000000,10000000};
int month[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31};
int d1,d2,ans;

void checkandcreat(int n){
    if(n%100 == 29){
        if((n/10000)%100 == 0 && (n/10000)%400 !=0)//年份整百
            return ;
        else if((n/10000)%4)//年份不是整百
            return ;
    }
        
    for(int i = 0;i < 4;i++)
        n= n + ((n/key[i])%10) * key[7-i];

    if(d1<=n && n<=d2)
        ans++;
    return ;
}

int main(){
    
    cin >> d1 >> d2;
    int num;
    for(int i = 1;i <=12; i++){
        for(int j = 1; j <= month[i];j++ ){
            num = i*100 + j;
            checkandcreat(num);
        }
    }
    
    cout << ans;
    return 0;
}

拼数 2星

贪心 通过排序 cmp:两个数替换位置看哪个大

AC代码

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
typedef struct Node{
    string s;
}NUM;
NUM N[21];
string s1,s2;

bool cmp(NUM a,NUM b){
    s1 = a.s + b.s;
    s2 = b.s + a.s;
    return s1 > s2;
}

int main(){
    int n;
    cin >> n;
    int len;
    int key;
    for(int i = 0;i < n;i++){
        cin >> N[i].s;
        
    }
       sort(N,N + n,cmp);
    for(int i = 0;i < n;i++){
        cout << N[i].s;
    }
    return 0;
}

毒瘤xor 2星

贪心,每个二进制位单独判断,判断祝各位是1得到总和大,还是0的大

AC代码

#include <iostream>//前缀和 加异或
using namespace std;
int num[100010][32];
void fun(int i,int n){
    for(int t = 31;t > 0;t--){
        num[i][t] = n%2;
        n/=2;
    }
}
int main(){
    int n;
    int x;
    int l,r;
    int t;
    int key;
    cin >> n;
    for(int i = 1;i <= n;i++){
        cin >> x;
        fun(i,x);
    }
    for(int i = 1;i < 32;i++){
        for(int j = 1;j <= n;j++)
            num[j][i] += num[j-1][i];
    }
    cin >> t;
    
    for(int i = 0;i < t;i++){
        cin >> l >> r;
        x = 0;
        key = 1;
        for(int t = 31;t > 0;t--){//输出较小的能为0 就为0 
            if((num[r][t] - num[l-1][t])*2 < r -l+1 ){// <
                 x +=key;
            }
            key*=2;
        }
        cout << x << endl;
    }
    return 0;
}

字符串 2星

模拟,写个数组用来判断这个字母是否已经存了,存了几个

#include <iostream>
#include <cstring>
using namespace std;
char s[1000100];
int num[26];
bool check(void){
    for(int i = 0;i < 26;i++){
        if(!num[i])
            return false;
    }
    return true;
}

void incre(int n){
    if(0 <= n-'a' && n - 'a'< 26)
        num[n -'a']++;
}

void decre(int n){
    if(0 <= n -'a' && n - 'a'< 26)
        num[n -'a']--;
}

int main(){
    int ans = 2000000;
    int head = 0,last = 0;
    int len = 0;
    int getted = 0;
    cin >> s;
    len = strlen(s);
    for(int i = 0;i < 26;i++){
        incre(s[i]);
    }
    
    if(check()){
        cout << 26;
        return 0 ;
    }
    
    for(last = 26;last < len;last++){
        incre(s[last]);
        
        if(check()){//如果已经满了
            while(check()){//更新为子串得最优子串
                    decre(s[head]);
                    head++;
                }
            incre(s[--head]);
            if(last - head + 1 < ans){
                ans = last - head + 1;
            }
        }
        
    }
    cout << ans;
    return 0;
}

数学考试 2星

前缀和 + 枚举 求i-n最大连续k个数之和 ,然后枚举区间

AC代码

#include <iostream>
using namespace std;
long long  num[400020];
long long  maxk[400020];
long long max(long long a,long long b){
    return a > b?a:b;
}
int main(){
    int n,k,t;
    long long ans;
    cin >> t;
    for(int w = 0;w < t;w++){
        cin >> n >> k;
        for(int i = 1;i <= n;i++){
            cin >> num[i];
            num[i] += num[i-1];
        }
        maxk[n-k+2] = -100000000000;//可能都是负数
        for(int i = n-k+1;i > 0;i--){//i - n最大连续K个数之和
            maxk[i] = max(maxk[i+1],num[i+k-1] - num[i-1]);
        }
        
        ans = -10000000000000;
        for(int i = k;i <= n-k;i++)//边界要处理干净
                ans = max(num[i] - num[i - k] + maxk[i+1],ans);
        cout << ans << endl;
    }
    return 0;
}

「土」秘法地震 2星

二维差分 + 枚举 如果矩阵有值就是有建筑物

#include <iostream>
using namespace std;
int num[2000][2000];
int main(){
    int n,m,k;
    char c;
    cin >> n >> m >> k;
    for(int i = 1;i <= n;i++){
        for(int j = 1;j <=m;j++){
            cin >> c;
            if(c =='1')
                num[i][j] = 1;
            else if(num[i][j] == '0')
                num[i][j] = 0;
        }
    }
    int ans = 0;
    for(int i = 1;i <= n;i++){
        for(int j = 1;j <= m;j++){
            num[i][j] = num[i][j]+num[i-1][j] + num[i][j-1] - num[i-1][j-1];
            
        }
    }
    for(int i = k;i <= n;i++){
        for(int j = k;j <= m;j++){
            if(num[i][j] + num[i-k][j-k] - num[i-k][j] - num[i][j-k])
                ans++;
        }
    }
    cout << ans <<endl;
    return 0;
}

丢手绢 2星

尺取 小朋友A相邻的小朋友B的隔最远的为A的最远小朋友,或者A最远小朋友的右边

#include <iostream>
using namespace std;
long long num[100020];
int min(int a,int b){
    return a>b?b:a;
}
int max(int a,int b){
    return a>b?a:b;
}

int main(){
    int n;
    int ans = 0;
    long long len;
    cin >> n;
    for(int i = 1;i <= n;i++){
        cin >> num[i];
        num[i]+=num[i-1];
    }
    
    
    for(int i = 0, j = 1; j < n;){
        while((num[j] - num[i])*2 < num[n] && j < n)
            j++;
        if(j < n)
            ans = max(ans,max(num[j-1] - num[i],num[n] - num[j] + num[i]));
        else ans = max(ans,num[j-1] - num[i]);
        i++;
    }
    ans = max(ans,min(num[n] - num[n-1],num[n-1]));
    cout << ans;
    return 0;
}

排座椅 3星

贪心 把每对说话人要隔开的通道计数+1,再排序

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

typedef struct node{
    int key;
    int warth;
}ct;

ct countx[1020];
ct county[1020];
int min(int a,int b){
    return a>b?b:a;
}
bool cmp(ct a,ct b){
    return a.warth > b.warth;
}
bool cmp2(ct a,ct b){
    return a.key < b.key;
}

int main(){
    int n,m,k,l,d;
    cin >> m >> n >> k >> l >> d;
    int x1,y1,x2,y2;
    for(int i = 1;i <= d;i++){
        cin >> x1 >> y1 >> x2 >> y2;
        if(x1 == x2){
            county[min(y1,y2)].warth++;
            county[min(y1,y2)].key = min(y1,y2);
        }else{
            countx[min(x1,x2)].warth++;
            countx[min(x1,x2)].key = min(x1,x2);
         }
        
    }
    sort(countx,countx + m,cmp);
    sort(countx,countx + k,cmp2);
    sort(county,county + n,cmp);
    sort(county,county + l,cmp2);
    for(int i = 0;i < k;i++)
        cout << countx[i].key << " ";
    cout << endl;
    for(int i = 0;i < l;i++)
        cout << county[i].key << " ";
   
    return 0;
}

国王的游戏 3星

贪心+大数 求出大臣A、B。按AB排序优于按BA排序的不等式cmp,用cmp快排,求排序后最大值即可,乘法和除法的用大数实现

#include <iostream>
#include <algorithm>
#include <string>
#include <memory.h>
using namespace std;
typedef struct NODE{
    string left;
    string right;
}num;
num minister[1020];

string s3;

string multiplication(string s1,string s2){
    int ans[4000];
    memset(ans,0,sizeof(ans));

    s3 = "";
    int len1, len2, i, j;
    int index, key;
    char c;
   
    len1 = s1.length();
    len2 = s2.length();

    reverse(s1.begin(),s1.end());
    reverse(s2.begin(),s2.end());

    for (i = 0; i < len1; i++) //时间复杂度为n*m
    {
        for (j = 0; j < len2; j++)
        {
            // printf("%d %d\n",i,num);
            ans[i + j] += (s1[i] - '0') * (s2[j] - '0'); //从0开始逆序输出
            //ans[index+1] += (num/10);
        }
    }
    //个位为0^十位为2……

    for (index = 0; index < len1 + len2 + 10; index++) //循环条件要确保index完全走完数组长度
    {
        if (ans[index] > 9) //
        {
            ans[index + 1] += ans[index] / 10;
            ans[index] %= 10;
        }
    }

    while (ans[index] == 0 && index > 0) //省去高位
    {
        index--;
    }

    while (index >= 0) //逆序输出
    {
        c = '0' + ans[index];
        s3+=c;
        index--;
    }
   
    return s3;
}

bool cmp(num a,num b){
    string s1,s2;
    s1 = multiplication(b.right,b.left) ;
    s2 = multiplication(a.right,a.left);
   
    if(s1.length() > s2.length())
        return true;
    if((s1.length() == s2.length()) && s1.compare(s2) > 0)
       return true;
    return false;
}

string  max(string a,string b){
  
    if(a.length() > b.length())
        return a;
    if(a.length() == b.length() && a.compare(b) >0)    
        return a;
    return b;
}


string division(string s1,string s2)
{
    s3 = "";

    int ans[4000];
    memset(ans,0,sizeof(ans));

    int key,key1,len1,len2,i;

    len1 = s1.length();
    len2 = s2.length();
    key = len1 - len2;

    if ((key < 0) || (key == 0 && s1.compare(s2) < 0)) //小数除大数
    {
        
        s3 = "0";
        return s3;          //结束处理
    }

    key1 = key; //key1为原始位差

    while (key >= 0) //从最高位开始减,key表示,s1和s2的位差
    {
        //比较子串
        while (s1.compare(len1 - key - len2, len1, s2, 0, len2) < 0 && key >= 0) //给s2加的位差过大,s1<s2
        {
            if(len1 - key - len2 > 0 && s1[len1 - key -len2 -1] > '0')//s1前面已经有非零位 已经大于
                break;
            key--; //减小位差
        }

        if (key < 0) //位差小于0此时s1<s2 不能再减
            break;
        for (i = len2 - 1; i >= 0; i--) //从低位开始减 key1 = len1 -len2
        {
            s1[i + key1 - key] = s1[i + key1 - key] - s2[i] + '0';

            if (s1[i + key1 - key] < '0') //借位,因为s1>s2所以放心借位
            {
                s1[i + key1 - key] += 10;
                //if(i+key1-key>0)
                s1[i + key1 - key - 1] -= 1;
            }
        }
        ans[key]++; //减法次数加1
    }
    //最多有key1位
    while (!ans[key1]) //去掉前置0,逆序存放所以逆序输出
    {
        key1--;
    }

    char c;
    while (key1 >= 0) //逆序输出商
    {
        c = ans[key1] + '0';
        //printf("%d", ans[key1]);
        s3 += c;
        key1--;
    }

    return s3;
}

int main(){
    string king;
    string ans;
    int n;
    
    cin >> n;
    cin >> king >> ans;
    for(int i = 0;i < n;i++)
        cin >> minister[i].left >> minister[i].right;
    sort(minister,minister + n,cmp);
    
    ans = division(king,(minister[0].right));
    for(int i = 1;i < n;i++){
        king = multiplication(king,minister[i-1].left);
        ans = max(ans,division(king,minister[i].right));
    }
    cout << ans;
    //system("pause");
    return 0;
}

[SCOI2005]扫雷MINE 3星

枚举+检验

枚举第一个空有没有雷,一旦确定,根据第二列的地雷数,就可以确定哪个地方有雷,哪个地方没有雷,把格子填雷后,最后再判断最后一行第二列是统计地雷书是否与题目给出符合。答案 0-2

AC代码

#include <iostream>

using namespace std;
int num[10010][2];
int n;
int MOVE[3] = {-1,1,0};
bool right_index(int i){
    return 0 < i && i <=n;
}


    
int getsum(int i){
    int index;
    int sum = 0;
    for(int j = 0;j < 3;j++){
        index = MOVE[j] + i;
        if(right_index(index)){
            sum += num[index][0];
        }
    }
    return sum;
}

int dfs(int i,int key){
    int x = 0;
    int ans = 0;
    
    if(i > n){
        if(getsum(i-1) == num[i-1][1])
            return 1;
        else return 0;
    }
        
    num[i][0] = key;
    x = num[i][1] - getsum(i);
    
    if(x == 1)
        ans = dfs(i+1,1);
      
    else if(!x)
        ans =  dfs(i+1,0);
    num[i][0] = 0;//防止影响main的另一个dfs
    return ans;

}

int main(){
    
    cin >> n;
    for(int i = 1;i <=n;i++)
        cin >> num[i][1];
    cout << dfs(1,0) +  dfs(1,1) << endl;
    
    return 0;
}

起床困难综合症 3星

位运算+ 贪心+ 枚举
对于大于m的二进制位只求0通过防御门的这一位攻击,对于<=m的二进制位求01通过防御门的攻击,由于m不同,不一定<m的每个位都可以取到1如果可以选1但选0更优,那你就选0,之后的低位,选01都无所谓,因为已经确保了攻击力 <=m;

AC代码

#include <iostream>

using namespace std;
char s[200010][3];
int op[200010][32];
int num[32];
int ans[32][2];
long long fn[32];
int main(){
    int n,m;

    cin >> n >> m;
    for(int i = 0; i< n;i++){
        scanf("%s %d",s[i],&op[i][31]);
        
    }
    int index = 0;
    while(m){//低位到高位
        num[index] = m%2;
        m/=2;
        index++;
    }
    
    for(int i = 0;i < n;i++){//从低位到高位
        index = 0;
        while(op[i][31]){
            op[i][index] = op[i][31]%2;
            op[i][31]/=2;
            index++;
        }
    }
    
    int x,flag = 0;
    for(int i = 30;i>=0;i--){//高位到低位求01最后攻击到龙的数据
        if(num[i] || flag){
                x = 1;
            for(int j = 0;j < n;j++){
                if(s[j][0] =='A')
                    x &= op[j][i];
                else if(s[j][0] == 'O')
                    x |= op[j][i];
                else x^=op[j][i];
            }
            ans[i][1] = x;
            flag = 1;
        }
        x = 0;
        for(int j = 0;j < n;j++){
                if(s[j][0] =='A')
                    x&=op[j][i];
                else if(s[j][0] == 'O')
                    x|=op[j][i];
                else x^=op[j][i];
            }
        ans[i][0] = x;
    }
    
    long long result = 0;
    flag = 0;
    fn[0] = 1;
    for(int i = 1;i < 31;i++){
        fn[i] = fn[i-1]*2;
    }
    
    for(int i = 30;i >=0;i--){
        if(ans[i][0]){//0一定可以取到
            result+=fn[i];
            if(num[i]){
                flag = 1;//后面num[i]即使是0也可以取1
                continue;
            }
        }
        else if(num[i] || flag ){//可以取到1
                if( ans[i][1])
                      result += fn[i];
                else flag = 1;//不取1
        }
    }
    printf("%lld",result);
    return 0;
}                           

奇♂妙拆分 3星

枚举 判断拆分剩下的数是否已经有了

AC代码

#include <iostream>
#include <cmath>
#include <string.h>
using namespace std;
int num[20];
int len;
bool checkin(int n){
    for(int i = 0;i < len;i++){
       if(n == num[i])
           return false;
    }
    num[len++] = n;
    return true;
}

int main(){
    int T;
    cin >> T;
    int n;
    int ans;
    int x;
    for(int t = 0;t < T;t++){
        ans = 1;
        len = 0;
        
        cin >> n;
        if(n == 1){
            cout << 1 << endl;
            continue;
        }
        x = n;
        for(int i = 2;i <= sqrt(x);i++){
            if(x%i == 0){
                if(checkin(i)){//判断是否已经有了这个数
                    if(checkin(x/i)){//判断拆剩下的数是否重复
                         ans++;
                         x/=i;
                    }
                   else len--;//x/i重复,checkin(i)家的数要丢掉
                }
                
            }
        }
        
            ans++;//因为最后拆剩下了一个数
        cout << ans << endl;
    }
    return 0;
}

糖糖别胡说,我真的不是签到题目 3星

差分+思维 差分快速完成对区间的+1操作(发功),然后维护两组i-n的最大能力值max数组,从后往前看如果第i个能力值 < 另一组 max[i+1-n],这个糖糖一定会被消灭。

AC代码

#include <iostream>
using namespace std;
typedef struct node{
    int key;
    int dif;
}GNODE;
GNODE num[50020];
int d[50020];
//差分快速得到多次对每个不同区间进行操作后的最终结果
int main(){
    int n,m,T,ans = 0;
    int dist;
        cin >> T;
    for(int t = 0;t < T;t++){
        ans = 0;
        cin >> n >> m;
        for(int i = 1;i <= n;i++){
            cin >> num[i].dif >> num[i].key;
            d[i] = num[i].key - num[i - 1].key;
            //cout <<"d " <<  d[i] << endl;
        }
        for(int i = 1;i <= m;i++){
            cin >> dist;
            d[1]++;
            d[dist + 1]--;
        }
        for(int i = 1;i <= n;i++) d[i]+=d[i-1];
       
        int max1 = 0,max0 = 0;
        for(int i = n;i >= 1;i--){
            if(num[i].dif){
                if(d[i] >= max0){
                    ans++;
                    
                }
                max1 = max(max1,d[i]);
            }
            else{
                if(d[i] >= max1){
                    ans++;
                    
                }
                max0 = max(max0,d[i]);
            }
        }
        cout << ans << endl;
    }
    
    return 0;
}

「土」巨石滚滚 3星

贪心 冲撞一瞬间-ai稳定冲撞过程如果稳定性X<0 就散架,冲撞结束后+bi的稳定性。

为了使得尽可能的可以完成所有冲撞,要把冲撞结束稳定性增加的障碍物放前面,增加稳定性(如果连稳定性增加到可能的最大都不能完成所有冲撞,那么一定会失败,相反也要用尽可能大的稳定性X来面对大ai障碍物),对于ai < bi的障碍物把ai 从小到大排序,防止一开始就散架.对于ai > bi的障碍物 可以要按bi从大到小排序,可以用AB排序时YES,BA排序时NO的情况来证明。

AC代码

#include <iostream>
#include <algorithm>
using namespace std;
typedef struct Noder{//撞后稳定性增加从小到大排序
                            //a-b>0的把a小的放前面,
    long long a,b,c;// m =6 5 1,4 3
}node;
node num[500010];//要一直朝一个方向去证,比如一直证NO,或者YES,不要一会证YES一会证NO
bool cmp1(node x,node y){
    return x.c > y.c;
}
bool cmp2(node x,node y){
    return x.a < y.a;
}
bool cmp3(node x,node y){
    return x.b > y.b;
}
int main(){
    long long T,t,n,m,index;
    cin >> T;
    int flag = 0;
    for(int t = 0;t < T;t++){
        cin >> n >> m;
        for(int i = 0;i < n;i++){
            cin >> num[i].a >> num[i].b;
            num[i].c = num[i].b - num[i].a;
        }
            
        sort(num,num+n,cmp1);//左闭右开
        flag = 0;
        for(int i = 0;i < n;i++)
             if(num[i].c <0 ){//num[i].c=0的放前面
                 index = i;
                 flag = 1;
                 break;
             }
        if(flag){
            sort(num,num+index,cmp2);
        }
        else sort(num,num+n,cmp2);
        
        if(flag)
            sort(num + index,num + n,cmp3);//!!!!!!!假设AB过BA不过得到cmp3
        flag = 0;
        for(int i = 0;i < n;i++){
            
            if(m < num[i].a){
                cout <<"No"<<endl;
                flag = 1;
                break;
            }
            m += (num[i].b - num[i].a);
                
        }
        
           
        if(!flag)
            cout << "Yes" << endl;
    }
    return 0;
}

矩阵消除游戏 3星

二进制枚举+贪心
k >=n || k >=m意味着可以全选,否则把行枚举选完,就可以贪心的选大的列了。

AC代码

#include <iostream>
#include <algorithm>
using namespace std;
long long num[17][17];
long long c[17];
long long c1[17];
long long r[17];
bool cmp(long long x,long long y){
    return x > y;
}
int main(){
    long long ans = 0,sum = 0;
    int n,m,k;
    cin >> n >> m >> k;
    for(int i = 0;i < n;i++){
      
        for(int j =0;j < m;j++){
            cin >> num[i][j];
            r[i]+= num[i][j];
        }
            
    }
    for(int i = 0;i < m;i++){
        for(int j = 0;j < n;j++){
            c[i]+=num[j][i];
        }
    }
    if(k >= min(n,m)){
        sum = 0;
        for(int i = 0;i < n;i++)
            sum+=r[i];
        cout << sum << endl;
        return 0;
    }
        int t = k;
        int x = 0;
        int index = 0;
    for(int i = 0;i <= (1<<n)-1;i++){
         t = k;
         x = i;
         index = 0;
         sum = 0;
        for(int j = 0;j < m;j++) c1[j] = c[j];
        
        while(x){
            if(x&1){
                sum+=r[index];
                t--;
                for(int j = 0;j < m;j++) c1[j] -= num[index][j];
            }
            x>>=1;
            index++;
            
        }
        if(t < 0)
            continue;
        else if(!t){
            ans = max(ans,sum);
        }
        else{
            sort(c1,c1 + m,cmp);
            t--;
            while(t>=0){
                sum+=c1[t];
                t--;
            }
            ans = max(ans,sum);
        }
            
    }
    cout << ans << endl;
    return 0;
}

牛牛的木板 4星

①前缀和 + 尺取(m) + 双指针
②也可以使用队列存放清洗木板位置

AC代码

#include <algorithm>

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int 
     * @param m int 
     * @param a intvector 
     * @return int
     */

    int solve(int n, int m, vector<int>& a) {//前缀和
       int index,sum = 0;
       for(int i = n; i;i--){
           a[i]=a[i-1];
        }
        a[0] = 0;
        for(int i = 2;i <= n;i++){
           a[i]+=a[i-1];
        }
        index = 0;
        for(int i = 1;i <= n;i++){
            if(a[i]-a[index] + m >= i - index)
                continue;
            else{
                sum = max(sum, i - index-1);
                while(a[i]-a[index] + m < i - index){
                 index++;
                }
            }
        }
        
        sum = max(sum,n - index);
        
        return sum;
    }
};

②队列

#include <algorithm>

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int 
     * @param m int 
     * @param a intvector 
     * @return int
     */
    queue<int> get;
    int solve(int n, int m, vector<int>& a) {
        int maxnum = 0,sum = 0;
        
       
        for(int i = 0;i < n;i++){
            if(a[i]){
                 sum++;
                 
            }else{
                if(get.size() == m){
                    maxnum = max(maxnum,sum);
                    sum = i - get.front();
                    
                    get.pop();
                    get.push(i);
                }else{
                    get.push(i);
                    sum++;
                }
                
            }
        }
        maxnum = max(maxnum,sum);
        cout << maxnum << endl;
        return maxnum ;
    }
};
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值