二中模拟赛 9.9

第一题sort 太菜了并不会

考试的时候暴力写炸了

70分(TLE)思路:可以发现对一个数x而言,加上小于lowbit(x)的数,都不影响它二进制下1个数的奇偶性。

所以,用新规则比较两个数x,y,当它们二进制下1个数的奇偶性相同时,加上小于min(lowbit(x), lowbit(y))的数都不影响它们的比较结果,必须一直加到第min(lowbit(x), lowbit(y))次时,两个数在二进制下1数量的奇偶性才会变成不同。

因此把所有的+1操作直接改为加上min(lowbit(x), lowbit(y))。

+快读 70分(然而不加快读也是70分)

 1 #include<cstdio>
 2 #include<algorithm> 
 3 using namespace std;
 4 const int N=100007;
 5 long long n,a[N];
 6 long long read()
 7 {
 8     char ch=getchar();int x=0,f=1;
 9     while(ch<'0'||ch>'9')
10     {
11         if(ch=='-') f=-1;
12         ch=getchar();
13     }
14     while(ch>='0'&&ch<='9')
15     {
16         x=x*10+ch-'0';
17         ch=getchar();
18     }
19     return x*f;
20 }
21 long long lowbit(long long x)
22 {
23     return x&(-x);
24 }
25 long long cnt(long long x)
26 {
27     long long c=0;
28     while(x)
29     {
30         x-=lowbit(x);c++;
31     }
32     return c;
33 }
34 bool comp(int x,int y)
35 {
36     while((cnt(x)&1)==(cnt(y)&1))
37     {
38         long long c=min(lowbit(x),lowbit(y));
39         x+=c,y+=c;
40     }
41     return cnt(x)&1;
42 }
43 int main()
44 {
45     n=read();
46     for(int i=1;i<=n;i++) a[i]=read();
47     sort(a+1,a+1+n,comp);
48     for(int i=n;i>=1;i--) printf("%lld ",a[i]);
49     return 0;
50 }

改这道题改了一晚上,期间翻阅了其他人的代码,发现有一份和我写的差不多(甚至可以说思路一模一样)的代码,然而它100。不知道自己哪里出了问题。

 

 

第二题study 很典型的二分答案题,然而考试的时候死活没想到。普及组难度。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=100007;
long long a[N],b[N],c[N],e[N],n;
long long ans;
bool pd(long long x)
{
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        e[i]=x*b[i];
        if(e[i]<a[i]) cnt+=ceil(1.0*(a[i]-e[i])/c[i]);
        if(cnt>x) return 0;
    }
    return 1;
}
int main()
{
    scanf("%d",&n);
    long long l=1,r=0,ans;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
        r=max(r,a[i]);
    }
    while(l<=r)
    {
        long long mid=l+r>>1;
        if(pd(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%lld",ans);
    return 0;
}

这里有一个问题(似乎),虽然a数组不会溢出int,但x*b可能会溢出,所以要开long long,否则50分。

改了半个小时的惨痛教训。

 

第三题highway  先来看一下大佬的题解

枚举第k条边大小

将所有边减去k和0去max

每次暴力跑最短路即可

 

讲题的时候证明了为什么“将所有边减去k和0去max”在k不在最短路上时不会导致答案变小。

因为我太菜了,所以先来解释一下“将所有边减去k和0去max”这个操作。我对这个操作的理解是,枚举第k条边,设这条边的边长为x。

理想状态下,最短路上>=x的有k-1条边,剩下的<=x。此时如果把所有的边减去x和0去max,那么大于x的会剩下与x的差值,小于x的都变成0,即理想状态下的不取。此时跑最短路,再把删掉的k个x加回来,正好补给k本身和大于x的边,而对于小于k的边,因为国家政策免费,所以依然为0。

但并不是所有情况都是理想状态。但若大于x的边大于k,则权值太大,大于枚举真正的第k大的边的最短路,不会取到;

若大于x的边小于k,则最后的答案为x*k,多补到因为与0取max而等于0的边上了,大于枚举真正的第k大的路的最短路,不会取到。

似乎是这么理解的。

 

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int N=2007;
const long long INF=100000000000000;
struct egde{
    long long next,to,v;
}e[N],e2[N];
struct node{
    long long pos,dis;
    friend bool operator <(const node x,const node y)
    {
        return x.dis>y.dis;
    }
};
priority_queue<node>q;
int n,m,k,s,t,head[N],etot;
long long dis[N],ans;
bool vis[N];
void adde(int x,int y,int v)
{
    e2[++etot].to=y;
    e2[etot].v=v;
    e2[etot].next=head[x];
    head[x]=etot;
}
long long dijkstra()
{
    for(int i=1;i<=n;i++)
    {
        vis[i]=0;
        if(i!=s) dis[i]=INF;
    }
    q.push((node){s,0});
    while(!q.empty())
    {
        int u=q.top().pos;q.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].v)
            {
                dis[v]=dis[u]+e[i].v;
                if(!vis[v]) q.push((node){v,dis[v]});
            }
        }
    }
    return dis[t];
}
int main()
{
    ans=INF;int x,y,v;
    scanf("%d%d%d%d%d",&n,&m,&k,&s,&t);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&v);
        adde(x,y,v);
    }
    memcpy(e,e2,sizeof(e2));
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=m;j++) e[j].v=max(e2[j].v-e2[i].v,(long long)0);
        ans=min(ans,dijkstra()+e2[i].v*k);
    }
    printf("%lld",ans);
    return 0;
}

 

转载于:https://www.cnblogs.com/IvyLH03/p/11515729.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值