相邻交换

是一种很实用的证明贪心还有一些别的东西的正确性的方法。
尽管我的证明非常的不正经不完整甚至不正确
然而如果有dalao对证明过程有建议的话请直接提出!十分感谢。

国王游戏(game)

来源

NOIP2012Day1T2

题面

有n个人和一个国王,每个人(包括国王)左右手上都有一个数字,每个人的权值是排在他之前的人左手的数的乘积/他右手的数。求如何排列使得权值最大的人的权值最小。

分析

其实一开始看到最大值最小的想法是二分,但是看到这个问题觉得判断似乎也不大容易所以放弃这个想法。

(暂时忽略高精的部分,因为和题目思路无关)
假设现在前面的数字都排好了,后面的数字也都排好了,只剩下中间的两个人a,b需要排序。
可以发现a,b的顺序不影响后面的结果也不影响前面的结果。
那么假设x=在他们之前所有人左手的乘积。
如果a排在前面resa=max(x/r[a],x*l[a]/r[b])
如果b排在前面resb=max(x/r[b],x*l[b]/r[a])
那么要让res尽可能的小,则如果resa小则 a在前,反之b在前。
(其实这个证明并不完整),但是比赛时候推出这个东西差不多能意识到正确性以及怎么排序,同时推的过程并不长也很方便。

//因为有点长太占版面所以放在最后加…

Recover the Smallest Number

来源

pat 1038

题意

读入n个数字串,这些串可能有前导零或者全是零,现在把这些数字串排列之后使得组成的数字最小。输出的时候忽略前导零。

分析

其实这道题似乎是可以通过一些神奇的补位啊重复循环什么的来解决的但是看起来都很长很麻烦的样子…
这里还是假设前面后面都排好了然后来考虑中间两个数字串的关系。同样的可以发现前面那一段和后面那一段不受中间这部分的影响。
然后我们要做的就是让中间这一段最小。事实上这样的话只有两种可能a在b前或b在a前。
然后呢就判一判这两种接法的大小关系即可。

raspored

(应该是叫这个吧我英文不好...)

来源

COCI2011/2012 Contest#2 F

题意

有一个快递员送披萨。一共有n个人需要披萨。
对于每个人都有一个用餐时间t[i]和他所要的披萨的准备时间l[i]。如果送给这个人的时间比预计时间早k分钟,那么就这个人就会给快递员k元的小费,如果快递员迟到了k分钟,那么快递员就要给他k元的赔偿。
一共有m次,都会有一个人改变他的需求。
他们会更改他们的新用餐时间和要的披萨种类(也就是说披萨的制作时间也会随之改变)
求出每个更改需求之后这个快递员最多能获得多少小费。

分析

暂时忽略这群人修改他们的需求。来看看对于已知的所有l[i],t[i],如何排列能使得小费最多。
如果已经排列好了,数组t,l表示排列好之后的数组,来表示一下这个答案吧。
res=(t[1]-l[1])+(t[2]-l[1]+l[2])+(t[3]-l[1]+l[2]+l[3])…+(t[n]-l[1]-l[2]-l[3]…-l[n])
然后就发现t根本不影响排序…
然后来看怎么排序。是有两种方法的。

首先讲如标题所见的相邻交换
假设前面的已经排序好了,后面的也已经排序好了,就只剩下中间的没有排了。假设现在要处理的披萨是a,b,那么这两个披萨的顺序也是只有两种可能的。
a在b前:res+=(l[a])+(l[a]+l[b])
b在a前:res+=(l[b])+(l[b]+l[a])
然后同样的比较一下然后确定哪个在前面即可。

还有一种方法就是,排序不等式虽然这个东西我也不大会
可以发现上式可以转化成res=t[i]-l[i]*i (1<=i<=n)
然后发现l[i]是从小到大排的。

以下是瞎扯
还有一种我比赛时候的方法。模拟故事情节。如果我是一个厨师,我就先炒时间最短的。因为没过1分钟,都会有x(还没有收到披萨的人的个数)的损失,那么我要尽快的把这个损失给减小减小减小…然后就可以发现是从小到大排了。


以下是code

国王游戏(game)
#include<cstdio>
#include<algorithm>
#include<cstring>
#define M 1005
#define ll long long
using namespace std;

void read(int &x){
    x=0; char c=getchar();
    for (; c<'0'; c=getchar());
    for (; c>='0'; c=getchar())x=(x<<3)+(x<<1)+(c^'0');  
}

struct AC{int a,b;}a[M];
int x,y,n;
bool cmp(AC x,AC y){
    return max(y.b,x.b*x.a)<max(x.b,y.b*y.a);
}

struct CCC{

    struct big{
        int a[5005];
        void clear(){memset(a,0,sizeof(a)); a[0]=1;}
        void get(int x){
            a[1]=x;
            for (; a[a[0]]>=10; ){
                a[a[0]+1]+=a[a[0]]/10; a[a[0]]%=10;
                a[0]++;
            }
        }
        void cheng(int x){
            int i;
            for (i=1; i<=a[0]; i++)a[i]*=x;
            for (i=1; i<=a[0]; i++){
                a[i+1]+=a[i]/10;
                a[i]%=10;               
                if (a[a[0]+1])a[0]++;
            }           
        }   
        big chu(int x){
            int i,now=0;
            big res; res.clear();
            for (i=a[0]; i&&now<x; i--)now=now*10+a[i];
            if (now<x)return res;
            res.a[0]=i+1;
            res.a[i+1]=now/x; now%=x;
            for (; i; i--){
                now=now*10+a[i];
                res.a[i]=now/x;
                now%=x;             
            }
            return res;
        }   
        void pt(){
            int i;
            for (i=a[0]; i; i--)printf("%d",a[i]);      
        }
    };

    void cmp(big &x,big y){
        if (x.a[0]<y.a[0]){x=y; return;}
        if (x.a[0]>y.a[0])return;
        int i;
        for (i=x.a[0]; i; i--){
            if (x.a[i]<y.a[i]){x=y; return;}
            if (x.a[i]>y.a[i])return;        
        }       
    }


    void solve(){
        int i;
        big res,cnt;
        res.clear(); cnt.clear(); cnt.get(x);
        for (i=1; i<=n; i++){
            big num=cnt.chu(a[i].b);
            cmp(res,num);
            cnt.cheng(a[i].a);  
        }
        res.pt();
    }       
}p100;

int main(){
    int i;
//  freopen("game.in","r",stdin);
//  freopen("game.out","w",stdout);
    read(n);
    read(x); read(y);
    for (i=1; i<=n; i++)read(a[i].a),read(a[i].b);
    sort(a+1,a+n+1,cmp);
    p100.solve();
    return 0;
}
Recover the Smallest Number
#include<bits/stdc++.h>
using namespace std;
int n;
string s[10005],ans;
bool cmp(string a,string b){
    return a+b<b+a;
}

int main(){
    scanf("%d",&n);
    int i,len;
    for (i=1; i<=n; i++)cin>>s[i];
    sort(s+1,s+n+1,cmp);
    for (i=1; i<=n; i++)ans+=s[i];
    len=ans.size();
    for (i=0; i<len&&ans[i]=='0'; i++);
    if (i==len)puts("0");
    else for (; i<len; i++)printf("%c",ans[i]);
    return 0;
} 
raspored
#include<bits/stdc++.h>
#define M 200002
#define mo 1000000007
#define LL long long
using namespace std;


void read(int &x){
    char c; x=0;
    for (c=getchar(); c<48;)c=getchar();
    for (; c>=48; c=getchar())x=(x<<1)+(x<<3)+(c^48);    
}

int lowbit(int x){
    return (x&(-x));
}
int n,m,p1[M];
LL p2[M];

void add1(int x,int num){
    int i=x;
    for (; i<=M;){
        p1[i]+=num;
        i+=lowbit(i);
    }
}

void add2(int x,LL num){
    int i=x;
    for (; i<=M;){
        p2[i]+=num;
        i+=lowbit(i);
    }
}

int sum1(int x){
    int i=x,sum=0;
    for (; i>0;){
        sum+=p1[i];
        i-=lowbit(i);
    }
    return sum;
}

LL sum2(int x){
    int i=x;
    LL sum=0;
    for (; i>0;){
        sum+=p2[i];
        i-=lowbit(i);
    }
    return sum;
}

LL sum,summ;
int T[M],L[M],a[M];
int main(){
    //freopen("input.txt","r",stdin);
    read(n); read(m);
    int i,j,k,l,no,be;
    for (i=1; i<=n; i++){
        read(T[i]); read(L[i]); a[i]=L[i];
        sum+=T[i];
    }
    sort(a+1,a+n+1);
    for (i=1; i<=n; i++){
        summ+=1LL*(n-i+1)*a[i];
        add1(a[i],1);
        add2(a[i],a[i]);
    }
    printf("%lld\n",sum-summ);
    int x,t,num;
    for (i=1; i<=m; i++){
        read(x); read(t); read(l); sum=sum-T[x]+t; T[x]=t; num=L[x]; L[x]=l;
        if (l<num){
            summ-=1ll*(n-sum1(num-1))*num;
            add1(num,-1); add1(l,1);    
            summ+=1LL*(n-sum1(l)+1)*l;
            summ+=sum2(l)-sum2(num-1);
            add2(num,-num); add2(l,l);
        }
        else if (l>num){
            summ-=1ll*(n-sum1(num)+1)*num;
            add1(num,-1); add1(l,1);    
            summ+=1LL*(n-sum1(l-1))*l;
            summ+=sum2(l-1)-sum2(num);
            add2(num,-num); add2(l,l);
        }
        printf("%lld\n",sum-summ);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值