noip济南清北冲刺班day2

小时のblog 小时のblog     2022-09-25     508

关键词:

 

题解:

贪心+dp

30% N<=5  5!枚举一下

20%  高度没有的时候,高度花费就不存在了,将ci排序,

从小到大挨个跳。另外,20% 准备跳楼没有花费,那么跳

楼的高度一定是从小到大,或者是从大到小。所以按照hi从

小到大排序,那么跳楼一定是排序后连续的一段。枚举第一

栋楼从哪开始跳。对于100% (1)hi从小到大排序,最后高度

的花费一定是hend-hstart。那么start—end中间楼的高度就

不会造成影响,只需要将start—end中间的楼排序,取小的ci。

(2)现在跳在第i栋楼上,已经跳了j栋楼了的最小花费。

f[i][j]—>min{ f[k][j+1]+c[k]+abs{h[i]-h[k]} }

最后答案是枚举i,j。

代码:

暴力挂了20

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define maxn 60
using namespace std;

int n,t,ans,flag1,flag2,flag3;
int vis[maxn];

struct Build{
    int h,c;
}b[maxn];

inline int read(){
    int x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}

bool cmp1(Build a,Build b){
    return a.c<b.c;
}

bool cmp2(Build a,Build b){
    return a.h<b.h;
}

void dfs(int nxt,int now,int sum){
    sum+=b[now].c;
    if(sum>t)return;
    ans=max(ans,nxt-1);
    for(int i=1;i<=n;i++){
        if(vis[i]==0){
            vis[i]=1;
            if(nxt==1){
                dfs(nxt+1,i,sum);
                vis[i]=0;
            }else {
                dfs(nxt+1,i,sum+abs(b[now].h-b[i].h));
                vis[i]=0;
            }
        }
    }
    return;
}

int main(){
    freopen("meet.in","r",stdin);
    freopen("meet.out","w",stdout);
    n=read();flag1=true;flag2=true;
    for(int i=1;i<=n;i++)b[i].c=read();
    for(int i=1;i<=n;i++)b[i].h=read();
    t=read();
    if(n<=5){
        dfs(1,0,0);
        printf("%d\n",ans);
        fclose(stdin);fclose(stdout);
        return 0;
    }
    for(int i=2;i<=n;i++){
        if(b[i].h!=b[i-1].h){
            flag1=false;break;
        }
    }
    if(flag1){
        int ret=0;
        sort(b+1,b+n+1,cmp1);
        for(int i=1;i<=n;i++){
            if(t-b[i].c>0){
                ret++;t-=b[i].c;
            }
        }
        printf("%d\n",ret);
        fclose(stdin);fclose(stdout);
        return 0;
    }
    for(int i=1;i<=n;i++){
        if(b[i].c){
            flag2=false;break;
        }
    }
    if(flag2){
        sort(b+1,b+n+1,cmp2);
        for(int len=1;len<=n;len++){
            flag3=false;
            for(int st=1;st+len-1<=n;st++){
                int ed=st+len-1,pre=b[st].h,f=0;
                for(int i=st;i<=ed;i++){
                    f+=b[i].h-pre;
                    pre=b[i].h;
                }
                if(f<=t)flag3=true,ans=max(ans,len);
            }
            if(flag3==false)break;
        }
        printf("%d\n",ans);
        fclose(stdin);fclose(stdout);
        return 0;
    }
    dfs(1,0,0);
    printf("%d\n",ans);
    fclose(stdin);fclose(stdout);
    return 0;
}
50

 正解

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

int n,t,ans;
int f[55][55];

struct Build{
    int c,h;
    bool operator < (const Build &a) const{
        h<a.h;    
    }
}a[55];

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i].c);
    for(int i=1;i<=n;i++)scanf("%d",&a[i].h);
    scanf("%d",&t);
    sort(a+1,a+n+1);
    memset(f,0x3f,sizeof(f));
    for(int i=0;i<=n;i++)f[i][1]=a[i].c;
    for(int i=1;i<=n;i++)
     for(int j=1;j<=i;j++){
         for(int k=1;k<i;k++)
       f[i][j]=min(f[i][j],f[k][j-1]+(j==1?0:a[i].h-a[k].h)+a[i].c);
     }
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
      if(f[i][j]<=t)ans=max(ans,j);
    printf("%d\n",ans);
    return 0;
}
AC

 

 

题解:

假设

a1<a2<a3.....<an

b1<b2<b3...<b(n*(n-1)/2)

那么b1=a1+a2,b2=a1+a3....

a2+a3=bx,然后枚举bx,

根据

a1+a2=b1

a1+a3=b2

a2+a3=bx,

三个方程三个未知数,在b数组中删去b1,b2,bx,

那么b数组中剩下最小的一定是

a1+a4,a2+a4,a3+a4....都知道了,然后从b数组中删去。

重复上步。

代码还明白。

v#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=310;

int n,m,res[maxn],ans[maxn][maxn],z[maxn*maxn],cnt;

bool use[maxn*maxn];

void check(int p)
{
    memset(use,false,sizeof(use));
    if ((z[1]+z[2]+z[p])&1) return;
    res[1]=(z[1]+z[2]+z[p])/2-z[p];
    res[2]=z[1]-res[1];
    res[3]=z[2]-res[1];
    use[1]=use[2]=use[p]=true;
    for (int a=4,b=3;a<=n;a++)
    {
        while (b<=m && use[b])
            b++;
        if (b>m) return;
        res[a]=z[b]-res[1];
        use[b]=true;
        for (int c=2;c<a;c++)
        {
            if (res[c]>res[a]) return;
            int v=res[c]+res[a];
            int p=lower_bound(z+1,z+m+1,v)-z;
            if (z[p]!=v) return;
            int px=p;
            while (px && z[px]==z[p])
                px--;
            px++;
            while (px<=m && z[px]==z[p] && use[px])
                px++;
            if (z[px]!=z[p] || use[px]) return;
            p=px;
            use[p]=true;
        }
    }
    cnt++;
    for (int a=1;a<=n;a++)
        ans[cnt][a]=res[a];
}

int main()
{
    freopen("city.in","r",stdin);
    freopen("city.out","w",stdout);

    scanf("%d",&n);
    m=n*(n-1)/2;
    for (int a=1;a<=m;a++)
        scanf("%d",&z[a]);
    sort(z+1,z+m+1);
    for (int a=3;a<=m;)
    {
        check(a);
        int b=a;
        while (b<=m && z[b]==z[a])
            b++;
        a=b;
    }
    printf("%d\n",cnt);
    for (int a=1;a<=cnt;a++)
        for (int b=1;b<=n;b++)
        {
            printf("%d",ans[a][b]);
            if (b==n) printf("\n");
            else printf(" ");
        }

    return 0;
}
std

 

 题解:

 又写挂的暴力.

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100009
#define maxm 70009
using namespace std;

int n,m,gg,cnt,ans,pp;
int a[maxn],sum[10008][500],p[10008];

struct Q{
    int l,r,v,id;
}q[maxn];

inline int read(){
    int x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}

void slove1(){
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=m;i++){
        int l,r,p,v,ans=0;
        l=read();r=read();p=read();v=read();
        for(int j=l;j<=r;j++)
         if(a[j]%p==v)ans++;
        printf("%d\n",ans);
    }
}

void slove2(){
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=m;i++){
        q[i].l=read();q[i].r=read();pp=read();q[i].v=read();
    }
    for(int i=1;i<=n;i++){
        a[i]%=pp;if(!p[a[i]])p[a[i]]=++cnt;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=cnt;j++)sum[i][j]=sum[i-1][j];
        sum[i][p[a[i]]]++;
    }
    for(int i=1;i<=m;i++){
        int L=q[i].l,R=q[i].r,V=q[i].v;
        printf("%d\n",sum[R][p[V]]-sum[L-1][p[V]]);
    }
}

int main(){
    freopen("light.in","r",stdin);
    freopen("light.out","w",stdout);
    n=read();m=read();
    if(n<=1000&&m<=1000){
      slove1();    
      fclose(stdin);fclose(stdout);
      return 0;
    }else 
    slove2();
    fclose(stdin);fclose(stdout);
    return 0;
}
30

正解:下面是自己都mengbi的笔记

暴力30%

P相同的30%,将ai%p的值存在vector里。

每次询问时寻找vector,用个数据结构维护一下。

1 5 2 3 4   q=3

1 2 2 0 1

V=0  4

V=1  1 5

V=2  2 3

二分找。空间大小是O(n),可以用vector去搞。

100%做法

对于每一个p需要处理每一个数%p之后在0—n-1的哪一个位置。

100%的数据和之前的区别是p不一样了是吧。只考虑p<=10^4。

可以对每一个p做一个预处理,然后建一个0—n-1的数组,每个p有个O(n)的

空间,那么有O(np),会TLE。所以不能对所有的p进行处理。那么对哪些p进

行处理呢?可以对1<=p<=100,进行处理。对于1<=p<=100,套用60%的做法,

像之前预处理,空间100*n,询问去数组里二分找就可以了。P>100怎么做呢?

我们不可能对那么多p进行处理,考虑每个询问,l-r,能被统计进答案的数是哪些?

是v,v+p,v+2p…..V+KP<=10^4,p>100,那么k<100,说明不到100个数。求p+kv

在l—r中出现了多少次????在数组里二分求。就是把60%的模p改成不模p。

代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=310;

int n,m,res[maxn],ans[maxn][maxn],z[maxn*maxn],cnt;

bool use[maxn*maxn];

void check(int p)
{
    memset(use,false,sizeof(use));
    if ((z[1]+z[2]+z[p])&1) return;
    res[1]=(z[1]+z[2]+z[p])/2-z[p];
    res[2]=z[1]-res[1];
    res[3]=z[2]-res[1];
    use[1]=use[2]=use[p]=true;
    for (int a=4,b=3;a<=n;a++)
    {
        while (b<=m && use[b])
            b++;
        if (b>m) return;
        res[a]=z[b]-res[1];
        use[b]=true;
        for (int c=2;c<a;c++)
        {
            if (res[c]>res[a]) return;
            int v=res[c]+res[a];
            int p=lower_bound(z+1,z+m+1,v)-z;
            if (z[p]!=v) return;
            int px=p;
            while (px && z[px]==z[p])
                px--;
            px++;
            while (px<=m && z[px]==z[p] && use[px])
                px++;
            if (z[px]!=z[p] || use[px]) return;
            p=px;
            use[p]=true;
        }
    }
    cnt++;
    for (int a=1;a<=n;a++)
        ans[cnt][a]=res[a];
}

int main()
{
    freopen("city.in","r",stdin);
    freopen("city.out","w",stdout);

    scanf("%d",&n);
    m=n*(n-1)/2;
    for (int a=1;a<=m;a++)
        scanf("%d",&z[a]);
    sort(z+1,z+m+1);
    for (int a=3;a<=m;)
    {
        check(a);
        int b=a;
        while (b<=m && z[b]==z[a])
            b++;
        a=b;
    }
    printf("%d\n",cnt);
    for (int a=1;a<=cnt;a++)
        for (int b=1;b<=n;b++)
        {
            printf("%d",ans[a][b]);
            if (b==n) printf("\n");
            else printf(" ");
        }

    return 0;
}
std

 

题解:贪心

遇到右括号和待匹配的左括号匹配。没有待匹配的左括号那么

将这个右括号改成左括号。最后将剩余的左括号一半改成右括

号进行匹配。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100009
using namespace std;

char s[maxn];
int len,top,ans;

int main(){
    freopen("shower.in","r",stdin);
    freopen("shower.out","w",stdout);
    scanf("%s",s+1);len=strlen(s+1);
    for(int i=1;i<=len;i++){
        if(s[i]=='(')top++;
        else {
            if(top)top--;
            else ans++,top++;
        }
    }
    printf("%d\n",ans+top/2);
    fclose(stdin);fclose(stdout);
    return 0;
}
AC

 

 

 

题解:线性筛+前缀和+二分

那么求连续k个质数的和就是O(1)的了。

发现,在前面选k个比在后面选k个小,这说明是有单调性的,二分k个

数最后一个数的位置。也可以二分第一个数。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1000009
#define LL long long
using namespace std;

LL n;
int t,k,cnt;
int check[maxn],prime[maxn];
LL sum[maxn];

inline LL read(){
    LL x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}

void Prime(){
    check[1]=true;
    for(int i=2;i<=1000000;i++){
        if(!check[i])prime[++cnt]=i,sum[cnt]=sum[cnt-1]+i;
        for(int j=1;j<=cnt&&i*prime[j]<=1000000;j++){
            check[i*prime[j]]=true;
            if(i%prime[j]==0)break;
        }
    }
}

int main(){
    freopen("diary.in","r",stdin);
    freopen("diary.out","w",stdout);
    scanf("%d",&t);
    Prime();
    for(int i=1;i<=t;i++){
        n=read();scanf("%d",&k);
        int l=1,r=cnt;
        LL ans=0;
        while(l<=r){
            int mid=(l+r)>>1;
            int p=mid-k;
            if(p>=0){
                LL gg=sum[mid]-sum[p];
                if(gg<=n){
                    ans=gg;
                    l=mid+1;
                }else r=mid-1;
            }else l=mid+1;
        }
        if(ans==0)printf("-1\n");
        else printf("%I64d\n",ans);
    }
    fclose(stdin);fclose(stdout);
    return 0;
}
AC

 

 

 

题解:

30%暴力建树+floyed

查看详情

济南清北学堂游记day2.

在大佬云集的地方被直线碾压是什么样的体验?大概就是210和1030的差别。大概就是高质量机械键盘和空气的区别。回来的路上,我一直在想,我到底是不是一个高三的?大概也是能找到以前在家和学校训练时的不足,对算法的... 查看详情

2017-10-5清北刷题冲刺班p.m

套路exLCS魔方  查看详情

2017-10-6清北刷题冲刺班p.m

1.数组异或2.侦探游戏3.棋盘迷宫  查看详情

2017-10-6清北刷题冲刺班a.m

1.角谷猜想   2.刀塔   3.反击数   查看详情

2017清北济南考前刷题day2morning

期望得分:100+30+60=190实际得分:100+30+30=160 T1 最优方案跳的高度一定是单调的 所以先按高度排序dp[i][j]跳了i次跳到j枚举从哪儿跳到j转移即可 #include<cstdio>#include<cstring>#include<iostream>#include<algorith 查看详情

2017-10-5清北刷题冲刺班a.m

行列式#include<iostream>#include<cstdio>#definemaxn500010usingnamespacestd;intn,m,mod,l,r,x,y,b[maxn],a[maxn],cnt;voiddfs(intnow[],intsz){if(sz<=2){for(inti=1;i<=sz;i++)b[++cnt]=now[i]; 查看详情

2017-10-3清北刷题冲刺班p.m

 a【问题描述】你是能看到第一题的friends呢。——hja给你一个只有小括号和中括号和大括号的括号序列,问该序列是否合法。【输入格式】一行一个括号序列。【输出格式】如果合法,输出OK,否则输出Wrong。【样例输... 查看详情

2017-10-4清北刷题冲刺班p.m

P102zhxa【问题描述】你是能看到第一题的friends呢。——hja两种操作:1、加入一个数。2、询问有多少个数是?的倍数。【输入格式】第一行一个整数?,代表操作数量。接下来?行,每行两个数???,?。其中???表示是哪种操作,第... 查看详情

2017-10-1清北刷题冲刺班p.m.

一道图论好题(graph)TimeLimit:1000ms  MemoryLimit:128MB 题目描述LYK有一张无向图G={V,E},这张无向图有n个点m条边组成。并且这是一张带权图,不仅有边权还有点权。LYK给出了一个子图的定义,一张图G’={V’,E’}被称... 查看详情

2017-10-3清北刷题冲刺班a.m

P99zhxa【问题描述】你是能看到第一题的friends呢。——hja怎么快速记单词呢?也许把单词分类再记单词是个不错的选择。何大爷给出了一种分单词的方法,何大爷认为两个单词是同一类的当这两个单词的各个字母的个数是... 查看详情

2017-10-2清北刷题冲刺班a.m

一道图论神题(god)TimeLimit:1000ms  MemoryLimit:128MB 题目描述LYK有一张无向图G={V,E},这张无向图有n个点m条边组成。并且这是一张带权图,只有点权。LYK想把这个图删干净,它的方法是这样的。每次选择一个点,将它删掉,... 查看详情

2017-10-1清北刷题冲刺班a.m

位运算1(bit)TimeLimit:1000ms  MemoryLimit:128MB 题目描述LYK拥有一个十进制的数N。它赋予了N一个新的意义:将N每一位都拆开来后再加起来就是N所拥有的价值。例如数字123拥有6的价值,数字999拥有27的价值。假设数字N的价值... 查看详情

2017-10-4清北刷题冲刺班a.m

P101zhxa【问题描述】你是能看到第一题的friends呢。——hjaHja拥有一套时光穿梭技术,能把字符串以超越光速的速度传播,但是唯一的问题是可能会GG。在传输的过程中,可能有四种情况:1、字符串没有发生改变。2、字符串... 查看详情

2017-10-7清北刷题冲刺班p.m

测试A同花顺文件名输入文件输出文件时间限制空间限制card.cpp/c/pascard.incard.out1s512MB题目描述所谓同花顺,就是指一些扑克牌,它们花色相同,并且数字连续。现在我手里有n张扑克牌,但它们可能并不能凑成同花顺。我现在想知... 查看详情

2017-10-7清北刷题冲刺班a.m

测试A消失的数字文件名输入文件输出文件时间限制空间限制del.cpp/c/pasdel.indel.out1s512MB题目描述现在,我的手上有n个数字,分别是a1,a2,a3,...,an。我现在需要删除其中的k个数字。当然我不希望随随便便删除,我希望删除k个数字之... 查看详情

考前冲刺班成绩

 一个蒟蒻的成绩单、、、、 Day预计分数实际分数rank备注Day1上午16015099 Day1下午607061 Day2上午13011037 Day2下午2302309              &nbs 查看详情

noip2017金秋冲刺训练营杯联赛模拟大奖赛day2

T1模拟+排序,先把n个公司贪成合法,再在剩下的天数中找最大值注意不要统计2-t<0的天数1#include<cstdio>2#include<vector>3#include<iostream>4#include<algorithm>5#definelllonglong6usingnamespacestd;7longlongn,m,s,k,e 查看详情