qbday1

16 篇文章 0 订阅
7 篇文章 0 订阅

这个周末,Joe 一如既往的拿出了外卖的点餐单。菜单上从上到下列着 N 个菜, 每个菜 Joe 会列出一个美味值。Joe 这次希望从菜单上连续地点 K 个菜,并且美 味值之和最大。
但在计算美味值之和时,Joe 有自己的一套计算方法:由于他会按照顺序享受这 K 个菜,并且越吃越后面的菜他就越享受,所以对于他吃的第 i 个菜,设它的美 味值为 D,美味值之和就会加上 D*i。例如,如果他要顺序吃美味值为 3, 8, 5 的 菜,那么美味值之和为 3 + 8*2 + 5*3 = 34。
Joe 给出了这 N 个菜的美味值,他想知道所能达到最大的美味值之和。

t1 dish
这个题用前缀和模拟,1*1,2*2,3*3,4*4,5*5-2*1 ,3*2, 4*3 ,5*4 ,6*5
你会发现少了个1-4的和,多了个5*6
所以维护前缀和就行了

#include<cstdio>
#include<iostream>
using namespace std;
int s[1100000],n,k,a[1199999];
long long ans,tot;
int main(){
    freopen("dish.in","r",stdin);
    freopen("dish.out","w",stdout);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),s[i]=s[i-1]+a[i];
    for(int i=1;i<=k;i++) tot+=i*a[i];
    ans=tot;
    for(int i=k+1;i<=n;i++){
        tot-=a[i-k];
        tot-=s[i-1]-s[i-k];
        tot+=k*a[i];
        ans=max(tot,ans);
    }
    printf("%lld",ans); 
}

t2 champion

ancelot 市近期要举办大奖赛啦!住在市里的市民都十分兴奋,Morgan 也不例 外。他查了一下比赛的信息,发现比赛一共由 N 场,并且每一场的门票价格可能 会不相等。Morgan 留给比赛的预算是 K 元;他想知道,一共有多少种买票的方 案,使得门票之和不超过 K 呢?
60
背包f[j]表示花j元钱的方案数

#include<cstdio>
int n,k,a[1999999];
long long f[1999999];
int main(){
    freopen("champion.in","r",stdin);
    freopen("champion.out","w",stdout);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    f[0]=1;
    for(int i=1;i<=n;i++)
    for(int j=k;j>=a[i];j--)
    f[j]+=f[j-a[i]];
    for(int i=1;i<=k;i++)f[i]+=f[i-1];
    printf("%lld",f[k]);
} 

100
k’th number的变式
用折半搜索,2^40太大
2^20就ok了
先处理处前一半的组合,与后一半的组合;
排序
然后再枚举第一个里的,二分出第一个小于k的,加上前面的
也可以用two point。。。zhw说的。。。。
用两个指针搞

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n;long long a[45],k,ans,b[2][1<<21];
void dfs(bool opt,int l,int r,long long s){

    if(l<=r)
    {   
        b[opt][++b[opt][0]]=s+a[l];
        dfs(opt,l+1,r,s+a[l]);
        dfs(opt,l+1,r,s);
    }
}
int main(){
    freopen("champion8.in","r",stdin);
    freopen("champion.out","w",stdout);
    scanf("%d%lld",&n,&k);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    b[0][0]=b[1][0]=1;
    dfs(0,1,n/2,0);
    dfs(1,n/2+1,n,0);
    sort(b[0]+1,b[0]+b[0][0]+1);
    sort(b[1]+1,b[1]+b[1][0]+1);
    int r=b[1][0];
    for(int i=1;i<=b[0][0];i++){
        while(b[1][r]+b[0][i]>k) r--;
        //if(i>r) break;
        ans+=r;
    }
    printf("%lld",ans);
}

t3
hidden
Irene 想用以下的方法加密一条信息(这是她从密码学书上自学来的):
假定这条信息可以用一个字符串 S 表示,其中 S=BCAAD.(其中‘.’代表字符串结 尾)。Irene 首先把 S 的所有循环同构串写下来(所谓循环同构即是不断地把字符 串开头的字符移动到尾端):
BCAAD.
CAAD.B
AAD.BC
AD.BCA
D.BCAA
.BCAAD
接下来她会把这些字符串都排序:
.BCAAD
AAD.BC
AD.BCA
BCAAD.
CAAD.B
D.BCAA
接下来她会把这些字符串的最后一位按照顺序写下来得到加密串 T=DCA.BA
现在 Irene 发现在密码学的书上写着一条来历不明的加密串 T。她迫切地知道, 如果信息是按照这种方式加密的,那么原串是什么?

因为是按字典序排的,且字母顺序不会变,所以你只要把他们排个序,就知道第一列的序列了
这样就知道一个字母后面的了,第一个是从最后一个过去的。
然后相同的字母你给他编个号,就不相同了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
struct st{
    char s;
    int t;
};
bool cmp(const st &a,const st &b){
    return a.s<b.s||a.s==b.s&&a.t<b.t;
}
char q[31000];
st a[31000],b[31000];
int last[31000],x;
int main(){
    freopen("hidden.in","r",stdin);
    freopen("hidden.out","w",stdout);
    scanf("%s",q+1);
    for(int i=1;i<=strlen(q+1);i++) a[i].s=q[i],a[i].t=i,b[i].t=i,b[i].s=a[i].s;
    sort(a+1,a+1+strlen(q+1),cmp);
    for(int i=1;i<=strlen(q+1);i++){

        last[b[i].t]=a[i].t;
        if(b[i].s=='.') x=b[i].t;
    }
    //for(int i=1;i<=strlen(a+1);i++) printf("%d",last[b[i]]);
    int w=last[x];
    while(x!=w){
        printf("%c",b[w].s);
        w=last[w];
    }
    printf(".");
}

t4
backets
课堂上,Felix 刚刚学习了关于括号序列的知识。括号序列是一个只由左括号“(” 和右括号“)”构成的序列;进一步的,一个合法的括号序列是指左括号和右括号能 够一一匹配的序列。
如果用规范的语言说明,一个合法的括号序列可以有以下三种形式:
1S=“”(空串),S 是一个合法的括号序列;
2S=XY,其中 X,Y 均为合法的括号序列,则 S 也是一个合法的括号序列;
3S=(X),其中 X 为合法的括号序列,则 S 也是一个合法的括号序列。
这时老师在黑板上写出了一个了括号序列:“()))()”。 Felix 一眼就看出这个序列并不是合法的括号序列。
这时老师提出了一个这样的问题:能否在序列中找出连续的一段,把这一段里面
的左括号变成右括号,右括号变成左括号,变换之后整个序列可以变成合法的呢?
Felix 想到,可以把[3..5]进行调换,这样序列就会变为()(()),是一个合法的序列。 很明显,不止有一种方法可以使整个序列变合法。
这时,老师又在黑板上写出了一个长度为 N 的括号序列。Felix 想,能否对这个 序列进行至多一次变换,使它变合法呢?
这个题暴力50,可以枚举从哪里翻转,n^2
然后在判断是不是合法的序列,n的,所以是n^3*t
100用动规
f[i][j][k]指到第i位,有j个’(‘,k代表翻没翻转

#include<cstdio>
#include<cstring> 
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
char a[9990];
int t,f[2][5001][3];
int main(){
    freopen("brackets.in","r",stdin);
    freopen("brackets.out","w",stdout);
    scanf("%d\n",&t);
    while(t--){

        scanf("%s",a+1);int n=strlen(a+1);
        memset(f[0],0,sizeof f[0]);
        f[0][0][0]=1;int pre=0,nex=1;
        for(int i=1;i<=n;i++)
        {
            memset(f[nex],0,sizeof f[nex]);
            for(int j=0;i+j-1<=n&&j<=i;j++)
            {

            if(f[pre][j][0]){//为翻转
                if(a[i]=='(') f[nex][j+1][0]=1;
                else if(a[i]==')'&&j>0) f[nex][j-1][0]=1;

                if(a[i]==')') f[nex][j+1][1]=1;
                else if(a[i]=='('&&j>0) f[nex][j-1][1]=1;
            }
            if(f[pre][j][1]){//在反转
                if(a[i]==')') f[nex][j+1][1]=1;
                else if(a[i]=='('&&j>0) f[nex][j-1][1]=1;

                if(a[i]=='(') f[nex][j+1][2]=1;
                else if(a[i]==')'&&j>0) f[nex][j-1][2]=1;
            }
            if(f[pre][j][2]){//已翻转
                if(a[i]=='(') f[nex][j+1][2]=1;
                else if(a[i]==')'&&j>0) f[nex][j-1][2]=1;
            }
            }
            swap(nex,pre);
        }


        if(f[pre][0][0]||f[pre][0][1]||f[pre][0][2]) printf("possible\n");
        else printf("impossible\n");
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值