• NOIP2012提高组题解


    (D1T1) (Vigenère)密码 ((OK))

    (D1T2) 国王游戏 ((OK))

    (D1T3) 开车旅行

    (D2T1) 同余方程 ((OK))

    (D2T2) 借教室 ((OK))

    (D2T3) 疫情控制

    因为最近时间比较紧,所以紫题一律跳过,等最后一个星期不联考的时候再回来填坑.

    (D1T1)就字符串模拟题,刚开始看错题了,题目给的是密钥和密文,要求明文.注意区分一下大小写.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    char s1[1005],s2[1005];
    char b[26]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
    char a[26]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
    int main(){
    	scanf("%s%s",s1+1,s2+1);
    	int k=strlen(s1+1),n=strlen(s2+1);
    	for(int i=1;i<=k;++i)//把密钥补全
    		for(int j=1;i+j*k<=n;++j)s1[i+j*k]=s1[i];		
    	for(int i=1;i<=n;++i){
    		if(s2[i]>='A'&&s2[i]<='Z'){
    			if(s1[i]>='A'&&s1[i]<='Z'){
    				int x=s2[i]-'A'-(s1[i]-'A');
    				x+=26;printf("%c",a[x%26]);
    			}
    			if(s1[i]>='a'&&s1[i]<='z'){
    				int x=s2[i]-'A'-(s1[i]-'a');
    				x+=26;printf("%c",a[x%26]);
    			}
    		}
    		if(s2[i]>='a'&&s2[i]<='z'){
    			if(s1[i]>='A'&&s1[i]<='Z'){
    				int x=s2[i]-'a'-(s1[i]-'A');
    				x+=26;printf("%c",b[x%26]);
    			}
    			if(s1[i]>='a'&&s1[i]<='z'){
    				int x=s2[i]-'a'-(s1[i]-'a');
    				x+=26;printf("%c",b[x%26]);
    			}
    		}
    	}
    	printf("
    ");return 0;
    }
    
    

    (D1T2)恩,很经典的贪心题了,见过好多次了.本题结论是通过贪心证明方法(---)邻项微扰法证的.因为后面(40)分是高精,所以我懒得再写代码了,就口胡一下证明过程吧.

    假设最优方案中有两位大臣(i)(i+1),它们之前((1)~(i-1))位大臣左手乘积为(sum).那么此时产生的贡献是(max(frac{sum}{b_i},frac{sum*a_i}{b_{i+1}})),如果交换这两位大臣,那么产生的贡献是(max(frac{sum}{b_{i+1}},frac{sum*a_{i+1}}{b_{i}})).为了下文表示方便,按照出场顺序我们把这四个整数依次记为(k_1,k_2,k_3,k_4).

    首先根据式子显然有(k_1<k_4,k_2>k_3),因为前面那种是最优方案,所以(max(k_1,k_2)<max(k_3,k_4)),那么可以推得(k_2<k_4.)

    (frac{sum*a_i}{b_{i+1}}<frac{sum*a_{i+1}}{b_{i}})

    所以有(sum*a_i*b_i<sum*a_{i+1}*b_{i+1}),同时约掉(sum)

    (a_i*b_i<a_{i+1}*b_{i+1})

    所以本题的贪心策略就是按照左手右手的乘积从小到大排序.

    (D1T3)咕咕咕.

    (D2T1)最近考过两次了,扩欧的模板题.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline ll read(){
        ll x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    ll a,b,x,y;
    inline void exgcd(ll a,ll b,ll &x,ll &y){
    	if(!b){x=1;y=0;return;}
    	exgcd(b,a%b,x,y);
    	ll z=x;x=y;y=z-y*(a/b);
    }
    int main(){
    	a=read();b=read();exgcd(a,b,x,y);
    	printf("%lld
    ",(x%b+b)%b);
        return 0;
    }
    
    

    (D2T2),刚开始看到这道题其实是看错题了,以为是要求出所有不能满足要求的请求.然后看这些操作其实就是线段树的区间查询最小值和区间增加(负数),所以直接写的线段树模板,当然在看清题目后发现还是可以用线段树写啊.题目只要求第一个不能被满足的请求.

    然后发现这样的话,还可以二分答案(mid),这时只要检查是否有教室的前缀和大于该教室给定的那个数即可.因为如果第(mid)个请求时,有一个教室的前缀和大于该教室给定的那个数,那么第(mid+1)个请求时,那个教室的前缀和只会更大.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=1e6+5;
    int n,m,ask_min;
    int tot[N],minn[N<<2],add[N<<2];
    inline void build(int p,int l,int r){
    	if(l==r){minn[p]=tot[l];add[p]=0;return;}
    	int mid=(l+r)>>1;
    	build(p<<1,l,mid);build(p<<1|1,mid+1,r);
    	minn[p]=min(minn[p<<1],minn[p<<1|1]);
    }
    inline void pushdown(int p,int l,int r,int mid){
    	if(!add[p])return;
    	add[p<<1]+=add[p];add[p<<1|1]+=add[p];
    	minn[p<<1]+=add[p];minn[p<<1|1]+=add[p];
    	add[p]=0;
    }
    inline void ask(int p,int l,int r,int ql,int qr){
    	if(ql<=l&&qr>=r){ask_min=min(ask_min,minn[p]);return;}
    	int mid=(l+r)>>1;pushdown(p,l,r,mid);
    	if(ql<=mid)ask(p<<1,l,mid,ql,qr);
    	if(qr>mid)ask(p<<1|1,mid+1,r,ql,qr);
    }
    inline void change(int p,int l,int r,int ql,int qr,int val){
    	if(ql<=l&&qr>=r){add[p]+=val;minn[p]+=val;return;}
    	int mid=(l+r)>>1;pushdown(p,l,r,mid);
    	if(ql<=mid)change(p<<1,l,mid,ql,qr,val);
    	if(qr>mid)change(p<<1|1,mid+1,r,ql,qr,val);
    	minn[p]=min(minn[p<<1],minn[p<<1|1]);
    }
    int main(){
    	n=read();m=read();
    	for(int i=1;i<=n;++i)tot[i]=read();
    	build(1,1,n);
    	for(int i=1;i<=m;++i){
    		int z=read(),x=read(),y=read();
    		ask_min=1<<30;ask(1,1,n,x,y);
    		if(ask_min<z){printf("-1
    %d
    ",i);return 0;}
    		change(1,1,n,x,y,-z);
    	}
    	puts("0");
        return 0;
    }
    

    二分答案当然全方位(时空复杂度,码量)吊打线段树:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=1e6+5;
    int n,m,x[N],y[N],z[N],tot[N],sum[N];
    inline bool check(int mid){
    	for(int i=1;i<=n;++i)sum[i]=0;
    	for(int i=1;i<=mid;++i)sum[x[i]]+=z[i],sum[y[i]+1]-=z[i];	
    	int now=0;
    	for(int i=1;i<=n;++i){
    		now+=sum[i];
    		if(now>tot[i])return false;
    	}
    	return true;
    }
    int main(){
    	n=read();m=read();
    	for(int i=1;i<=n;++i)tot[i]=read();
    	for(int i=1;i<=m;++i)z[i]=read(),x[i]=read(),y[i]=read();
    	int l=0,r=n,mid,ans;
    	while(l<=r){
    		mid=(l+r)>>1;
    		if(check(mid))ans=mid,l=mid+1;
    		else r=mid-1;
    	}
    	if(ans==n){puts("0");return 0;}
    	printf("-1
    %d
    ",ans+1);
        return 0;
    }
    
    
  • 相关阅读:
    数据源与连接池
    JavaBean
    JSP隐含对象
    kibana 报错 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed
    JS中key-value存取
    JS判断数组中是否包含某个值
    数据库的事务
    net 查看版本号
    同行右边浮动
    CodeFirst
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11793192.html
Copyright © 2020-2023  润新知