NOIP 2011 提高组 Day2 校模拟 7.11

数论只会GCD 模拟只会猜题意 贪心只能过样例!!!!!

上午身体不适,基本上是强行趴在那写题。也不知道思路在哪个状态,看到T1第一想法居然连暴力都不是了。第一想法,居然是打表2333

T1: 计算系数

为什么我脑子里第一反应是打表…

是的这是我用画图打的草稿(还有一部分打到草稿纸上了)

然后我就写出来以下的天秀打表

//    if(a==b&&b==1){
//        if(k<=10){
//            switch(k){
//                case 0:{
//                    cout<<0;
//                    break;
//                }
//                case 1:{
//                    cout<<0;
//                    break;
//                }
//                case 2:{
//                    if(n==0||m==0){
//                        //2+0
//                        cout<<1;
//                    }
//                    else if(n==1){
//                        //1+1
//                        cout<<2;
//                    }
//                    else{
//                        cout<<0;
//                    }
//                    break;
//                }
//                case 3:{
//                    if(n==0||m==0){
//                        cout<<1;// 3+0
//                    }
//                    else if(n==2||m==2){
//                        //2+1
//                        cout<<3;
//                    }
//                    else{
//                        cout<<0;
//                    }
//                    break;
//                }
//                case 4:{
//                    if(n==3||m==3){
//                        //3+1
//                        cout<<4;
//                    }
//                    else if(n==2){
//                        cout<<6;
//                        //2+2
//                    }
//                    else if(n==0||m==0){
//                        cout<<1;//4+0
//                    }
//                    else{
//                        cout<<0;
//                    }
//                    break;
//                }
//                case 5:{
//                    if(n==4||m==4){//4+1
//                        cout<<5;
//                    }
//                    else if(m==2||n==2){
//                        //3+2
//                        cout<<10;
//                    }
//                    else if(m==0||n==0){
//                        //5+0
//                        cout<<1;
//                    }
//                    else{
//                        cout<<0;
//                    }
//                    break;
//                }    
//                case 6:{
//                    if(n==5||m==5){
//                        cout<<6;//5+1
//                    }
//                    else if(m==0||n==0){
//                        //6+0
//                        cout<<1;
//                    }
//                    else if(m==2||n==2){//4+2
//                        cout<<15;
//                    }
//                    else if(m==3){//3+3
//                        cout<<20;
//                    }
//                    else{
//                        cout<<0;
//                    }
//                    break;
//                }
//                case 7:{
//                    if(n==6||m==6){
//                        cout<<7;//6+1
//                    }
//                    else if(n==0||m==0){
//                        cout<<1;
//                        //7+0
//                    }
//                    else if(m==2||n==2){//5+2
//                        cout<<21;
//                    }
//                    else if(m==3||n==3){//4+3
//                        cout<<35;
//                    } 
//                    else{
//                        cout<<0;
//                    }
//                    break;
//                }
//                case 8:{
//                    
//                    break;
//                }
//                case 9:{
//                    
//                    break;
//                }
//                case 10:{
//                    
//                    break;
//                }            
//            }
//        }
//        else{
//            
//        }
//    }

打到8的时候,终于打通了我的脑回路。打表找规律…这行为是真滴流氓。

果然跟这个题目差不多,factor,类似于因子嘛(别挖我的十五级英语!!!),然后就发觉这东西是和前一项有联系的(而且还是相加的关系!)就是说,你的这个因子总是与上一个数的因子相关联。我就…痴痴地写出了以下正解…

#include<iostream>
#include<algorithm>
using namespace std;
long long a,b,k,n,m;
long long A[2000][2000];
long long ans;
const int Mogic=10007;
int power(int a,int b){
    int ans=1;
    for(;b;b>>=1){
        if(b&1){
            ans=(long long)ans*a%Mogic; 
        }
        a=(long long)a*a%Mogic;
    }
    //cout<<"返回值为"<<ans<<endl; 
    return ans;
}
int main(){
    freopen("factor.in","r",stdin);
    freopen("factor.out","w",stdout);
    cin>>a>>b>>k>>n>>m;
    A[2][2]=1;A[2][0]=1;
    A[2][1]=2;
    for(int j=3;j<=k;j++){
        A[j][0]=1;
        A[j][j]=1;
        A[j][j-1]=j;
        A[j][1]=j;        
    }
    //对于每个数来说
    //他的 i分子与 k-i是相同的
    for(int x=4;x<=k;x++){
        for(int i=2;i<=k/2;i++){
         A[x][i]=A[x-1][i]+A[x-1][x-i];
         A[x][i]%=Mogic;
         A[x][x-i]=A[x][i];
        }
    }
    if(a==b&&b==1){
        cout<<A[k][n]%Mogic;
    }
    else{
        //cout<<"调用二号"<<endl;
        A[k][n]%=Mogic;
        a%=Mogic;
        b%=Mogic;
        long long dele;
        dele=power(a,n)*power(b,m);
        dele%=Mogic;
        //cout<<"dele为 "<<dele<<endl; 
        //cout<<"A k n "<<A[k][n]<<endl;
        ans=A[k][n]*dele;
        ans%=Mogic;
        cout<<ans;
    }
}

记着开LongLong!

T2: 聪明的质监员

这个质检员的形容词是聪明?

一股腐败气息(哼)

 

 

当时拿到之后脑子还是懵兮兮的,直接跟着题走去模拟了。

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
const int MAXN=999999;
int n,m,s;
int w[MAXN];
int V[MAXN];
struct Factory{
    int a;
    int b;
}Zone[MAXN];
int ans;
int res;
bool Good[MAXN];
int main(){
    //freopen("qc.in","r",stdin);
    //freopen("qc.out","w",stdout); 
    res=9999999;
    int maxx=0;
    int maxx_forzone=0;
    int minxx_forzone=900;
    cin>>n>>m>>s;
    for(int i=1;i<=n;i++){
        cin>>w[i]>>V[i];
        maxx=max(maxx,w[i]);
    }    
    int x,y;
    for(int i=1;i<=m;i++){
        cin>>x>>y;
        Zone[i].a=x;
        Zone[i].b=y;
        maxx_forzone=max(maxx_forzone,y);
        minxx_forzone=min(minxx_forzone,x);
    }
    for(int W=1;W<=maxx;W++){
        //这题估计用二分 
        //二分这个W,找到一个会产生正数差和负数差的平衡点
        //只要这个W一大,那么相应的ans值就会减小。也就是说,
        //当二分出差值一正一副的时候,对比两边的差值,得出最终答案。 
        ans=0; 
        for(int i=minxx_forzone;i<=maxx_forzone;i++){
            if(w[i]>=W){
                Good[i]=true;
            }
            else{
                Good[i]=false;
            }
        }
        for(int i=1;i<=m;i++){
            int tot=0;
            int val=0;
            for(int j=Zone[i].a;j<=Zone[i].b;j++){
                if(Good[i]){
                    tot++;
                    val+=V[j];
                }
            }
            ans+=tot*val;
//            if(s-ans<0&&abs(s-ans)>res){
//                break;
//            }
            int index=abs(s-ans);
            res=min(res,index);
        }
        //cout<<"选择了 "<<W<<" 所产生的区间和为 "<<ans<<endl; 
    }
    cout<<res;
}

最有趣的是写着写着忽然就醒悟“哦!这是道二分题!!”

然后看了一眼表“我去我第一题是模拟了多久…还剩十分钟…算了把这题打完拉倒了,不管二分的事了”

喜爆零~!(好像是有个题目意思理解错了吗?)

正解其实也就是二分+前缀和了。没办法T1玩的太嗨,T2有思路了也没用。

#include<iostream>
#include<cstring>
#include<cmath>
#include <stdlib.h>
using namespace std;
const int MAXN=2000010;
int n,m;
long long ans;
long long S;
long long MAX_forR;
long long MIN_forL;
long long w[MAXN];
long long v[MAXN];
struct section{
    int l;
    int r;
}Zone[MAXN];
long long Y,sum;
long long FrontSum_n[MAXN];//你瞧,英语十级的气息 
long long FrontSum_v[MAXN];
bool check(int W){
    Y=0;sum=0;
    memset(FrontSum_n,0,sizeof(FrontSum_n));
    memset(FrontSum_v,0,sizeof(FrontSum_v));
    for(int i=1;i<=n;i++){
        if(w[i]>=W){
            FrontSum_n[i]=FrontSum_n[i-1]+1;
            FrontSum_v[i]=FrontSum_v[i-1]+v[i];    
        }
        else{
            FrontSum_n[i]=FrontSum_n[i-1];
            FrontSum_v[i]=FrontSum_v[i-1];    
        }
    }
    for(int i=1;i<=m;i++){
        Y+=(FrontSum_n[Zone[i].r]-FrontSum_n[Zone[i].l-1])*(FrontSum_v[Zone[i].r]-FrontSum_v[Zone[i].l-1]);
    }
    sum=llabs(Y-S);
    if(Y>S){
        return true;
    }
    else{
        return false;
    }
    
}
int main(){
    cin>>n>>m>>S;
    MIN_forL=999999999;
    ans=999999999999999;
    for(int i=1;i<=n;i++){
        cin>>w[i]>>v[i];
        MAX_forR=max(MAX_forR,w[i]);
        MIN_forL=min(MIN_forL,w[i]);
    }
    for(int i=1;i<=m;i++){
        cin>>Zone[i].l;
        cin>>Zone[i].r;
    }
    int left=MIN_forL-1;
    int right=MAX_forR+2;
    int mid;
    while(left<=right){
        mid=(left+right)/2;
        if(check(mid)){
            left=mid+1;
        } 
        else{
            right=mid-1;
        } 
        if(sum<ans){
            ans=sum;
        }
    }
    cout<<ans;
} 

(话说long long设定个最大值是真的麻烦…那个9写少了居然能炸一半的数据…)

T3: 观光公交

考场的时候没看,毕竟时间没了。

下来之后看了看题,感觉上来说…有点像以前做过的一个缆车的题…但又不一样。

这里有一个逻辑上的点,就是如果你开了氮气加速但到站了仍然需要等待最后一个来的人,那这波氮气就开的挺亏的。

公交车氮气加速,你这怕是速度与激情,牛逼!

代码来自LuoGu题解,看懂了但是真的不想再重新写一遍了…

/*last[ i ] : 最后一个人到达i站点的时间。
sum[ i ] : 到i站点的总人数。
enter[ i ] : 公交车到i站点的最少时间。
g[ i ] : 每个站点所能影响到的最远站点,即要求的影响。*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
//完全get,但精神受到了昨天175行重构代码结果有Bug没法Debug的重创
//今天!决定!不!重!构!啦! 
#define N 30001

using namespace std;
int n,m,k;
int dis[N],last[N],g[N],enter[N];
int ans,sum[N],maxx = -1;

struct node{
    int time,start,end;
}a[N];

inline void bus(int x){
    while(x){
        --x;
        g[n] = g[n - 1] = n;
        int tar;
        maxx = -1;
        for(int i = n - 2;i >= 1;-- i){
            if(enter[i + 1] <= last[i + 1])//下一个点如果等待 
                g[i] = i + 1;//最多影响到下一个
            else //不等待 
                g[i] = g[i + 1];//继续减少后面的时间 
        }
        for(int i = 1;i < n;++ i){//for边数 
            int tmp = sum[g[i]] - sum[i];//最多影响的人数 
            if(tmp > maxx && dis[i] > 0){
                maxx = tmp;
                tar = i;//标记最优情况减的点 
            }
        }
        ans -= maxx;//更新ans 
        dis[tar] --;//减掉dis  
        for(int i = 2;i <= n;++ i){
            enter[i] = max(enter[i - 1],last[i - 1]) + dis[i - 1];//重新更新enter 
        }
    }
    return;
}
int main(){
    scanf("%d%d%d",&n,&m,&k);// 
    for(int i = 1;i < n;++ i)
        scanf("%d",&dis[i]);//
    for(int i = 1;i <= m;++ i)
        scanf("%d%d%d",&a[i].time,&a[i].start,&a[i].end);
    for(int i = 1;i <= m;++ i){
        last[a[i].start] = max(last[a[i].start],a[i].time);//最后一个人到a[i].start站点的时间 和到这个点的时间取max 
        sum[a[i].end] ++;
    }
    enter[1] = last[1];
    for(int i = 1;i <= n;++ i)
        sum[i] += sum[i - 1];//到i站点的总人数 前缀和处理 

    for(int i = 2;i <= n;++ i)
        enter[i] = max(enter[i - 1],last[i - 1]) + dis[i - 1];//公车到i站点的最少时间 和最后到的时间取max 
    for(int i = 1;i <= m;++ i)
        ans += enter[a[i].end] - a[i].time;//处理出不加加速器的answer,后面就可以直接减啦~
    bus(k);
    printf("%d",ans);
    return 0;
}//

 

posted @ 2019-07-11 19:27  L1ngYi  阅读(182)  评论(0编辑  收藏  举报