2017 清北济南考前刷题Day 2 morning

期望得分:100+30+60=190

实际得分:100+30+30=160

T1

最优方案跳的高度一定是单调的

所以先按高度排序

dp[i][j] 跳了i次跳到j

枚举从哪儿跳到j转移即可

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 51

struct node
{
    int c,h;
}e[N];

int dp[N][N];

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); }
}

bool cmp(node p,node q)
{
    return p.h<q.h;
}

int main()
{
    freopen("meet.in","r",stdin);
    freopen("meet.out","w",stdout);
    int n;
    read(n);
    for(int i=1;i<=n;i++) read(e[i].c);
    for(int i=1;i<=n;i++) read(e[i].h);
    sort(e+1,e+n+1,cmp);
    memset(dp,63,sizeof(dp));
    for(int i=1;i<=n;i++) dp[0][i]=e[i].c;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            for(int k=1;k<j;k++)
                dp[i][j]=min(dp[i][j],dp[i-1][k]+e[j].h-e[k].h);
            dp[i][j]+=e[j].c;
        }
    int t;
    read(t);
    for(int i=n;i>=0;i--)
        for(int j=1;j<=n;j++)
            if(dp[i][j]<=t) { printf("%d",i+1); return 0; }
}

T2

设给出的数是b1,b2,……

解为a1,a2……

那么可以得到 b1=a1+a2,b2=a1+a3

如果再知道 a2+a3=X,就可以解出a1,a2,a3

在b中把b1 b2 X 删去

剩下的最小的一定是 a1+a4,解出a4

再把a2+a4 ,a2+a4 删去,剩下的最小的一定是a1+a5

以此类推,解出所有的a

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

int n,m,tot;

#define N 302

int b[N*N];

int ans[N*N][N],t[N];

bool use[N*N];

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar();     }
}

void work(int x)
{
    if((b[1]+b[2]+b[x])&1) return;
    t[2]=b[1]-b[2]+b[x]>>1;
    t[1]=b[1]-t[2];
    t[3]=b[2]-t[1];
    memset(use,false,sizeof(use));
    use[1]=use[2]=use[x]=true;
    int r,pos;
    for(int i=3,k=4;i<=m;++i)
    {
        if(use[i]) continue;
        t[k]=b[i]-t[1];
        for(int j=1;j<k;++j)
        {
            r=t[j]+t[k];
            pos=lower_bound(b+1,b+m+1,r)-b;
            if(b[pos]!=r) return;
            while(pos<m && use[pos] && b[pos]==r) pos++;
            if(b[pos]!=r) return;
            use[pos]=true;
        }
        k++;
    }
    tot++;
    for(int i=1;i<=n;i++) ans[tot][i]=t[i];
}

int main()
{
    freopen("city.in","r",stdin);
    freopen("city.out","w",stdout);
    read(n);
    m=n*(n-1)/2;
    for(int i=1;i<=m;++i) read(b[i]);
    sort(b+1,b+m+1);
    for(int i=3;i<=m;++i)
    {
        if(i>1 && b[i]==b[i-1]) continue;
        work(i);
    }
    printf("%d\n",tot);
    for(int i=1;i<=tot;++i)
    {
        for(int j=1;j<=n;++j) printf("%d ",ans[i][j]);
        printf("\n");
    }
}

T3

分块

因为街灯上的数不超过1e4,所以p最多有1e4个

用vector[i][j] 存下%i=j 的数的位置 i<=100

当p<=100 时,直接在vector[p][v] 里二分在区间[l,r]内的最左位置和最右位置

再用一个vector[i] 存下所有的街灯数位i的位置

当p>100 时,%p=v 的数 有v,v+p,v+2p……

直接枚举这些数,最多100个,在vector[i] 里 二分 在区间[l,r]内的最左位置和最右位置

#include<cstdio>
#include<vector>
#include<iostream>

using namespace std;

#define N 100001

int a[N];

vector<int>V1[101][101];
vector<int>V2[10001];

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar();  }
}

int main()
{
    freopen("light.in","r",stdin);
    freopen("light.out","w",stdout);
    int n,m;
    read(n); read(m);
    for(int i=1;i<=n;++i) read(a[i]),V2[a[i]].push_back(i);
    for(int i=1;i<=100;++i)
        for(int j=1;j<=n;++j)
            V1[i][a[j]%i].push_back(j);
    int l,r,p,v;
    int L,R,MID,TMP1,TMP2;
    int pos,tot;
    while(m--)
    {
        read(l); read(r); read(p); read(v);
        if(p<=100)
        {
            L=0; R=V1[p][v].size()-1;
            TMP1=TMP2=-1;
            while(L<=R)
            {
                MID=L+R>>1;
                if(V1[p][v][MID]>=l) TMP1=MID,R=MID-1;
                else L=MID+1;
            }
            if(TMP1==-1) { puts("0"); continue; }
            L=TMP1; R=V1[p][v].size()-1;
            while(L<=R)
            {
                MID=L+R>>1;
                if(V1[p][v][MID]<=r) TMP2=MID,L=MID+1;
                else R=MID-1;
            }
            if(TMP2==-1) { puts("0"); continue; }
            printf("%d\n",TMP2-TMP1+1);
        }
        else
        {
            pos=v; tot=0;
            while(pos<=10000)
            {
                L=0; R=V2[pos].size()-1;
                TMP1=TMP2=-1;
                while(L<=R)
                {
                    MID=L+R>>1;
                    if(V2[pos][MID]>=l) TMP1=MID,R=MID-1;
                    else L=MID+1;
                }
                if(TMP1==-1) { pos+=p; continue; }
                L=TMP1; R=V2[pos].size()-1;
                while(L<=R)
                {
                    MID=L+R>>1;
                    if(V2[pos][MID]<=r) TMP2=MID,L=MID+1;
                    else R=MID-1;
                }
                if(TMP2==-1) { pos+=p; continue; }
                tot+=TMP2-TMP1+1;
                pos+=p;
            }
            printf("%d\n",tot);
        }
    }
}

60分暴力

#include<vector>
#include<cstdio>
#include<iostream>

using namespace std;

#define N 100001

int n,m,a[N];

int P;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); }
}

namespace solve1
{
    int l,r,p,v,ans;
    void work()
    {
        while(m--)
        {
            read(l); read(r); read(p); read(v);
            ans=0;
            for(int i=l;i<=r;i++)
                if(a[i]%p==v) ans++;
            printf("%d\n",ans);
        }

    }
}

namespace solve2
{
    vector<int>V[10001];
    void work()
    {
        int l,r,p,v;
        int L,R,MID,TMP1,TMP2;
        for(int o=1;o<=m;o++)
        {
            read(l); read(r); read(p); read(v);
            if(o==1)
            {
                P=p;
                for(int i=1;i<=n;i++) V[a[i]%P].push_back(i);
            }
            if(v>10000 || !V[v].size()) { puts("0"); continue; }
            L=0,R=V[v].size()-1; TMP1=-1;
            while(L<=R)
            {
                MID=L+R>>1;
                if(V[v][MID]>=l) TMP1=MID,R=MID-1;
                else L=MID+1;
            }
            if(TMP1==-1 || V[v][TMP1]>r) { puts("0"); continue; }
            L=TMP1,R=V[v].size()-1; TMP2=-1;
            while(L<=R)
            {
                MID=L+R>>1;
                if(V[v][MID]<=r) TMP2=MID,L=MID+1;
                else R=MID-1;
            }
            if(TMP2==-1) { puts("0"); continue; }
            printf("%d\n",TMP2-TMP1+1);
        }
    }
}

void init()
{
    read(n); read(m);
    for(int i=1;i<=n;i++) read(a[i]);
    if(1ll*n*m<=1e6) solve1::work();
    else solve2::work();
}

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

时间: 2024-08-04 04:00:17

2017 清北济南考前刷题Day 2 morning的相关文章

2017 清北济南考前刷题Day 5 afternoon

期望得分:100+100+30=230 实际得分:0+0+0=30 T1 直接模拟 #include<cstdio> #include<iostream> using namespace std; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } #define N 1002

2017 清北济南考前刷题Day 1 morning

期望得分:100+100+50=250 实际得分:100+60+50=210 T2 二分 估错上界.估错复杂度 T1 立方数(cubic) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK定义了一个数叫“立方数”,若一个数可以被写作是一个正整数的3次方,则这个数就是立方数,例如1,8,27就是最小的3个立方数. 现在给定一个数P,LYK想要知道这个数是不是立方数. 当然你有可能随机输出一些莫名其妙的东西来骗分,因此LYK有T次询问~ 输入格式(cub

2017 清北济南考前刷题Day 5 morning

期望得分:100+100+0=200 实际得分: 坐标的每一位不是0就是1,所以答案就是 C(n,k) #include<cstdio> #include<iostream> using namespace std; const int mod=1e9+7; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0';

2017 清北济南考前刷题Day 3 morning

实际得分:100+0+0=100 T1 右上角是必败态,然后推下去 发现同行全是必胜态或全是必败态,不同行必胜必败交叉 列同行 所以n,m 只要有一个是偶数,先手必胜 #include<cstdio> using namespace std; int main() { freopen("star.in","r",stdin); freopen("star.out","w",stdout); int n,m; whi

清北考前刷题day7早安

清北考前刷题da7下午好

三向城 /* 原图一定是一棵完全二叉树. 根节点是x,左节点是x*2,右节点是x*2+1 转化为二进制往左右走就很明显了. */ #include<iostream> #include<cstdio> #include<cstring> #define ll long long using namespace std; int T,x,y,k,ans,pos; inline int read() { int x=0,f=1;char c=getchar(); while

清北考前刷题day6下午好

/* 贪心 负数一定不取 枚举最高位是1 且答案取为0的 位置, 更新答案. */ #include<iostream> #include<cstdio> #include<cstring> #define ll long long #define N 100010 using namespace std; int n; ll a[N],ans,sum[N]; char s[N]; ll read() { ll x=0,f=1;char c=getchar(); whi

2017清北精英班整理内容掌握考试题

精英班考试题 2017.2.10 题目名 工资 藏妹子之处 银河之星 源文件 money.cpp/c/pas excel.pas/cpp galaxy.cpp/c/pas 输入文件 money.in excel.in galaxy.in 输出文件 money.out excel.out galaxy.out 时间限制 1000MS 1000MS 1000MS 内存限制 256MB 128MB 256MB 测试点 10 10 10 测试点分值 10 10 10 第一题 工资 链接 第二题  藏妹子

2017清北学堂集训笔记——图论

我们进入一个新的模块——图论! emmmmm这个专题更出来可能有点慢别介意,原因是要划的图和要给代码加的注释比较多,更重要的就是...这几个晚上我在追剧!!我们的少年时代超级超级超级好看,剧情很燃啊!!咳咳,好吧下面回归正题. 一.图的存储: 1.邻接矩阵: 假设有n个节点,建立一个n×n的矩阵,第i号节点能到达第j号节点就将[i][j]标记为1(有权值标记为权值), 样例如下图: 1 /*无向图,无权值*/ 2 int a[MAXN][MAXN];//邻接矩阵 3 int x,y;//两座城市