暴力枚举

链接:Circus

题意:

给a,b两个字符串,代表n名演员是否会小丑和杂技

1代表表演小丑, 0 代表表演杂技,1 代表两个都表演, 0 代表两个都不表演

0                      , 1                      ,1                          , 0

要求选择n/2个演员在第一场演出,使得第一场的小丑和第二次的杂技数目相同

解析

可以直接暴力

遍历a和c的数目i,j

(i+j)是第一场上场的小丑,也是第二次上场的杂技的数目

b-((i+j)-(c-j)) 代表 在第一场上场的只会杂技的数目,(i+j)为第二场的杂技人员,((i+j)-(c-j))在第二场上场的只会杂技的人数

化简就是b+c-i-2*j

ac:

#include<bits/stdc++.h>
#define pb push_back
#define MAXN 5005
using namespace std;

char str[MAXN],ctr[MAXN];

int main()
{
    ios::sync_with_stdio(false);
    int n;
    cin>>n;
    cin>>str+1>>ctr+1;
    vector<int> aa,bb,cc,dd;
    for(int i=1;i<=n;i++)
    {
        if(str[i]=='1'&&ctr[i]=='0')
            aa.pb(i);
        else if(str[i]=='0'&&ctr[i]=='1')
            bb.pb(i);
        else if(str[i]=='1'&&ctr[i]=='1')
            cc.pb(i);
        else if(str[i]=='0'&&ctr[i]=='0')
            dd.pb(i);
    }
    for(int i=0;i<=(int)aa.size();i++)//a的数目
    {
        for(int j=0;j<=(int)cc.size();j++)//c的数目
        {
            int k=(int)bb.size()+(int)cc.size()-i-2*j;//b的数目
            if(k>=0&&k<=(int)bb.size())
            {
                int l=n/2-i-j-k;//d的数目
                if(l>=0&&l<=(int)dd.size())
                {

                    for(int a=0;a<i;a++)
                        cout<<aa[a]<<" ";
                    for(int b=0;b<j;b++)
                        cout<<cc[b]<<" ";
                    for(int c=0;c<k;c++)
                        cout<<bb[c]<<" ";
                    for(int d=0;d<l;d++)
                        cout<<dd[d]<<(d==l-1?"\n":" ");
                    return 0;
                }
            }
        }
    }
    printf("-1\n");
    return 0;
}

分宿舍:http://acm.hdu.edu.cn/showproblem.php?pid=6492

小伙们打算组团去参加。他们一共有 n+m+2k 个人,包括 n+k 个男生,m+k 个女生,其中 k 对男女生为异性情侣,现在他们要找房间住。房间有三种类型,双人间 a 元一间,三人间 b 元一间,这两种只能同性一起住。情侣间能住一对异性情侣,一间 c 元。除了情侣间以外,其他房间都可以不住满。
求最少花多少钱,能让小伙伴们都有地方住。

解析:

直接暴力遍历

先暴力k,然后暴力双人间,通过双人间可以直接算出三人间,注意精度

ac:
 

#include<bits/stdc++.h>
#define ll long long
#define MAXN 1005
using namespace std;
 
int main()
{
    ll t,n,m,k,a,b,c,nn,mm,kk;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld%lld%lld%lld%lld",&nn,&mm,&kk,&a,&b,&c);
        ll ans=1e15;
        ll sum;
        for(ll i=0;i<=kk;i++)
        {
            sum=0;
            n=nn+kk-i;
            m=mm+kk-i;
            sum+=i*c;
            ll aa=n/2+n%2;
            ll dd=1e15;
            if(aa)
            {
                for(ll j=0;j<=aa;j++)
                {
                    ll cc=(n-2*j)%3;
                    if(cc<0)
                        cc=0;
                    dd=min(dd,j*a+b*((n-2*j)/3+(cc!=0)));
                }
                sum=sum+dd;
            }
            ll bb=m/2+m%2;
            dd=1e15;
            if(bb)
            {
                for(ll j=0;j<=bb;j++)
                {
                    ll cc=(m-2*j)%3;
                    if(cc<0)
                        cc=0;
                    dd=min(dd,j*a+b*((m-2*j)/3+(cc!=0)));
                }
                sum+=dd;
            }
            ans=min(ans,sum);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

Knapsack Cryptosystem

题意:

给定1个数组,让你选若干个数,这些数的和为k

输出一个串长为该数组,该串1表示选择,0表示不选择

解析:

如果直接暴力枚举每种情况,呢么复杂度为2^36,显然不行

我们可以将串分为两部分,我们先求左边的,复杂度2^18

然后枚举右边的情况,2^18,如果s-右边的,在左边出现过,这样分配就可行

总的复杂度位2*2^18.

这样暴力就降低1维,这和枚举降维一个道理

<<和>>的优先级小于+,-,x,/

ac:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a[38];
unordered_map<ll,int> hash1;

int main()
{
    int n;
    ll s;
    scanf("%d%lld",&n,&s);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    int m=n/2;
    for(int i=0;i<=(1<<m)-1;i++)
    {
        ll sum=0;
        for(int k=0;k<=m-1;k++)
        {
            if((i>>k)&1==1)
                sum+=a[k+1];
        }
        hash1[sum]=i;
    }
    int kk=n-m;
    for(int i=0;i<=(1<<kk)-1;i++)
    {
        ll sum=0;
        for(int k=0;k<=kk-1;k++)
        {
            if((i>>k)&1==1)
                sum+=a[k+1+m];
        }
        if(sum==s||hash1[s-sum]!=0)
        {
            ll q=hash1[s-sum];
            for(int j=0;j<=m-1;j++)
                printf("%d",(q>>j)&1);
            for(int j=0;j<=kk-1;j++)
                printf("%d",(i>>j)&1);
            printf("\n");
            break;
        }
    }
    return 0;
}

Uniqueness

题意:

给定一个数组,你可以任选一个(l,r)中的数组元素删除,删除后剩下的数组元素都是唯一的(仅出现一次)

问你最小的(r-l+1)的大小

解析:

我用o(n)的方法被hack了,对于:6     3 1 4 3 2 4这组数据,解决不了

应当暴力处理这些区间

#include<bits/stdc++.h>
#define MAXN 2005
using namespace std;
int a[MAXN];
int b[MAXN];
int vis[MAXN];

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),b[i]=a[i];
    sort(b+1,b+n+1);
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(b+1,b+n+1,a[i])-b;
    //所以区间都要尝试一次,尝试能否在前面少取,而让后面可取更多
    int ans=1e9;
    for(int i=0;i<=n;i++)//i从0开始,尝试一次仅仅从后到前的遍历过程
    {
        memset(vis,0,sizeof(vis));
        int ok=0;
        for(int j=1;j<=i&&ok==0;j++)
        {
            if(vis[a[j]]==0)
                vis[a[j]]=1;
            else
                ok=1;
        }
        if(ok)
            break;
        int p=i;
        for(int j=n;j>i;j--)
        {
            if(vis[a[j]]){
                p=j;
                break;
            }
            else
                vis[a[j]]=1;
        }
        ans=min(ans,p-i);
    }
    printf("%d\n",ans);
    return 0;
}

http://acm.hdu.edu.cn/showproblem.php?pid=6739

Invoker
Time Limit: 15000/12000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)

 

Problem Description

在 dota2 中有一个叫做祈求者(Invoker)的英雄,在游戏中他有三个基础技能:冰(Quas),雷(Wex),火(Exort),每施展一个技能就可以获得相应属性的一个法球(element)。

但是祈求者同时最多只能有三个法球,即如果他在有三个法球的状态下又使用了某个法球技能,那么他会获得该法球,并失去之前三个法球中最先获得的一个。

不难得出,祈求者身上的三个法球的**无顺序**组合有 10 种,每一种都对应着一个组合技能:

1. 急速冷却(Cold Snap),无序组合 QQQ,用 Y 表示
2. 幽灵漫步(Ghost Walk),无序组合 QQW,用 V 表示
3. 寒冰之墙(Ice Wall),无序组合 QQE,用 G 表示
4. 电磁脉冲(EMP),无序组合 WWW,用 C 表示
5. 强袭飓风(Tornado),无序组合 QWW,用 X 表示
6. 灵动迅捷(Alacrity),无序组合 WWE,用 Z 表示
7. 阳炎冲击(Sun Strike),无序组合 EEE,用 T 表示
8. 熔炉精灵(Forge Spirit),无序组合 QEE,用 F 表示
9. 混沌陨石(Chaos Meteor),无序组合 WEE,用 D 表示
10. 超震声波(Deafening Blast),无序组合 QWE,用 B 表示

当祈求者拥有三个法球的时候,使用元素祈唤(Invoke)技能,用 R 表示,便可获得当前法球组合所对应的技能,同时原有的三个法球也不会消失,先后顺序的状态也不会改变。

现在给定一个技能序列,你想按照给定的顺序将他们一个一个地祈唤出来,同时你想用最少的按键来达到目标,所以你想知道对于给定的一个技能序列,最少按多少次键才能把他们都祈唤出来。

注意:游戏开始的时候,祈求者是没有任何法球的。

解析:

从前往后依次获得技能,要按顺序

我们暴力处理1->len的情况,最多计算6*6*100000次,我们预处理出每种字符串变化的最小步数,直接dp即可

ac:

#include<bits/stdc++.h>
#define ll long long
#define MAXN 1000005
using namespace std;
char s[MAXN];
int dp[MAXN][7];
int vv[11][7][11][7]={0};
string g[11][7];
int vg[30];

int gt(char x)//字母转数字
{
    return vg[x-'A'];
}

void init()//预处理
{
    vg['Y'-'A']=1;vg['V'-'A']=2;vg['G'-'A']=3;vg['C'-'A']=4;vg['X'-'A']=5;
    vg['Z'-'A']=6;vg['T'-'A']=7;vg['F'-'A']=8;vg['D'-'A']=9;vg['B'-'A']=10;//将字符串转化为字母
    g[1][1]="QQQ";g[1][2]="QQQ";g[1][3]="QQQ";g[1][4]="QQQ";g[1][5]="QQQ";g[1][6]="QQQ";
    g[2][1]="QQW";g[2][2]="QWQ";g[2][3]="WQQ";g[2][4]="QQW";g[2][5]="QWQ";g[2][6]="WQQ";
    g[3][1]="QQE";g[3][2]="QEQ";g[3][3]="EQQ";g[3][4]="QQE";g[3][5]="QEQ";g[3][6]="EQQ";
    g[4][1]="WWW";g[4][2]="WWW";g[4][3]="WWW";g[4][4]="WWW";g[4][5]="WWW";g[4][6]="WWW";
    g[5][1]="QWW";g[5][2]="WQW";g[5][3]="WWQ";g[5][4]="QWW";g[5][5]="WQW";g[5][6]="WWQ";
    g[6][1]="WWE";g[6][2]="WEW";g[6][3]="EWW";g[6][4]="WWE";g[6][5]="WEW";g[6][6]="EWW";
    g[7][1]="EEE";g[7][2]="EEE";g[7][3]="EEE";g[7][4]="EEE";g[7][5]="EEE";g[7][6]="EEE";
    g[8][1]="QEE";g[8][2]="EQE";g[8][3]="EEQ";g[8][4]="QEE";g[8][5]="EQE";g[8][6]="EEQ";
    g[9][1]="WEE";g[9][2]="EWE";g[9][3]="EEW";g[9][4]="WEE";g[9][5]="EWE";g[9][6]="EEW";
    g[10][1]="QWE";g[10][2]="QEW";g[10][3]="WEQ";g[10][4]="EWQ";g[10][5]="WQE";g[10][6]="EQW";

    for(int i=1;i<=10;i++)
    {
        for(int a=1;a<=6;a++)
        {
            for(int j=1;j<=10;j++)
            {
                for(int b=1;b<=6;b++)
                {
                    if(g[i][a]==g[j][b])//全等
                        vv[i][a][j][b]=0;
                    else if(g[i][a][1]==g[j][b][0]&&g[i][a][2]==g[j][b][1])//消1个
                        vv[i][a][j][b]=1;
                    else if(g[i][a][2]==g[j][b][0])//消2个
                        vv[i][a][j][b]=2;
                    else                            //全消
                        vv[i][a][j][b]=3;
                }
            }
        }
    }
}

int main()
{
    init();
    while(scanf("%s",s+1)!=EOF)
    {
        int len=strlen(s+1);
        for(int i=1;i<=6;i++)
            dp[1][i]=4;//开始3个+1个R
        for(int i=2;i<=len;i++)
            for(int j=1;j<=6;j++)
                dp[i][j]=1e9;
        for(int i=2;i<=len;i++)//暴力遍历从1~len的所以变化情况
        {
            for(int j=1;j<=6;j++)
            {
                for(int k=1;k<=6;k++)
                    dp[i][j]=min(dp[i][j],dp[i-1][k]+vv[gt(s[i-1])][k][gt(s[i])][j]+1);//每次至少一个R
            }
        }
        int ans=1e9;
        for(int i=1;i<=6;i++)//取最小值
            ans=min(dp[len][i],ans);
        printf("%d\n",ans);
    }
    return 0;
}

https://blog.csdn.net/weixin_41183791/article/details/86622672#commentBox

 

https://codeforces.com/contest/1029/problem/C

题意:

有n条线段,让你删除一条,使得剩下的线段的公共长度最大,问最大值

解析:

枚举删除每条线段,判断最长公共长度

法1:

L保存左端,R保存右端

#include<bits/stdc++.h>
#define MAXN 300005
using namespace std;
struct node
{
    int l,r;
}ee[MAXN];
unordered_map<int,int> visL,visR;
set<int> L,R;

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&ee[i].l,&ee[i].r);
        L.insert(ee[i].l);
        R.insert(ee[i].r);

        if(visL[ee[i].l]==0)
            visL[ee[i].l]=1;
        else
            visL[ee[i].l]++;

        if(visR[ee[i].r]==0)
            visR[ee[i].r]=1;
        else
            visR[ee[i].r]++;
    }
    if(n==1){
        printf("%d\n",ee[1].r-ee[1].l+1);
        return 0;
    }
    int maxs=0;
    for(int i=1;i<=n;i++)
    {
        visL[ee[i].l]--;
        visR[ee[i].r]--;
        if(visL[ee[i].l]==0){
            L.erase(ee[i].l);
        }
        if(visR[ee[i].r]==0){
            R.erase(ee[i].r);
        }
        auto it=L.end();
        it--;
        int aa=*it;
        int bb=*R.begin();
        maxs=max(maxs,max(0,bb-aa+1));
        visL[ee[i].l]++;
        visR[ee[i].r]++;
        if(visL[ee[i].l]==1){
            L.insert(ee[i].l);
        }
        if(visR[ee[i].r]==1){
            R.insert(ee[i].r);
        }
    }
    if(maxs>0){
        maxs--;
    }
    printf("%d\n",maxs);
    return 0;
}

法2:

set二维操作,容易又简便很多

#include<bits/stdc++.h>
#define MAXN 300005
using namespace std;
struct node
{
    int v,id;
    friend bool operator<(node a,node b)
    {
        if(a.v==b.v)
            return a.id<b.id;
        return a.v<b.v;
    }
};
struct vv
{
    int l,r;
}ee[MAXN];
set<node> L,R;

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&ee[i].l,&ee[i].r);
        L.insert(node{ee[i].l,i});
        R.insert(node{ee[i].r,i});
    }
    if(n==1){
        printf("%d\n",ee[1].r-ee[1].l+1);
        return 0;
    }
    int maxs=0;
    for(int i=1;i<=n;i++)
    {
        L.erase(node{ee[i].l,i});
        R.erase(node{ee[i].r,i});
        auto it=L.end();
        it--;
        int aa=it->v;
        int bb=R.begin()->v;
        maxs=max(maxs,max(0,bb-aa+1));
        L.insert(node{ee[i].l,i});
        R.insert(node{ee[i].r,i});
    }
    if(maxs>0)
        maxs--;
    printf("%d\n",maxs);
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值