zoukankan      html  css  js  c++  java
  • 2020.3.23 模拟赛游记 & 题解

    这次的模拟赛,实在是水。

    数据水,( exttt{std}) 水,出题人水,做题人也水。???

    游记就说一句:

    水。

    T1 metro

    弱智题。

    人均 (100pts).

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    int main(){
    	freopen("metro.in","r",stdin);
    	freopen("metro.out","w",stdout);
        int a=read(),b=read(),c=read(),d=read();
        int ans; if(a==c) ans=abs(b-d); //同一站
        else {
        	if(a==1) ans=abs(b-16)+abs(d-6);
        	else ans=abs(b-6)+abs(d-16);
    	} //不同站
    	if(ans<=5) puts("2");
    	else if(ans<=12) puts("3");
    	else if(ans<=20) puts("4");
    	else puts("5");
    	return 0;
    }
    
    

    T2 awake

    弱智题。

    除了没得 (100pts) 的,人均 (100pts).???

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    inline int num(string x) {
    	int s=0;
    	for(int i=0;i<x.size();i++) s=s*10+x[i]-'0';
    	if(s<'A'-'0') return s;
    	if(s=='J'-'0') return 11;
    	if(s=='Q'-'0') return 12;
    	if(s=='K'-'0') return 13;
    	return 14;
    } //对应的数字
    
    int main(){
    	freopen("awake.in","r",stdin);
    	freopen("awake.out","w",stdout);
        string t; int lim;
        int s=0; int ans=0;
        for(int i=1,x;i<=4;i++) {
        	cin>>t; x=num(t);
    //        cout<<t<<" "<<x<<endl;
        	if(x!=14) ans+=x;
        	else ans+=11,s++;
    	} //printf("%d %d
    ",ans,s);
    	lim=read();
    	for(int i=1;i<=s;i++) 
    	    if(ans>lim) ans-=10;
    	    else break; //只要超过,就不断置换
    	printf("%d
    ",(ans>lim)?0:ans);	 
    	return 0;
    }
    
    

    T3 contest

    弱智题。

    尽管弱智,还是错了几次。

    比方说要得到 (x) 枚金币,(y) 枚银币。

    那么,你肯定要进行 (x - 1) 轮,那么还剩 (y - (x - 1) = y - x + 1) 枚银币。

    这个数一定是偶数,否则肯定是 NO.

    边界问题要仔细!

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    int main(){
    	freopen("contest.in","r",stdin);
    	freopen("contest.out","w",stdout);
    	int T=read(),n,m; while(T--) {
    		n=read(),m=read();
    		if(!n) {puts("No");continue;}
    		if(n==1 && m) {puts("No");continue;}
    		if((n-1>m) || (m-n+1)&1) puts("No");
    		else puts("Yes");
    	}
    	return 0;
    }
    
    

    T4 homework

    这道题目,数据太水了!

    你只要输出 (leq Y) 的最大素数,就可以得到 (80pts).???

    暴力判断,可以得到 (100pts).???

    告诉你们,数据小暴力,数据大贪心,完全是错的!!!

    下面本人给出正解,吊打 ( exttt{std})!!!

    xyx出的题目太渣了吧,数据这么弱

    首先,如果 (X^2 geq Y),就输出最大素数。因为此时,(leq Y) 的所有合数都被筛掉了。

    否则,如果数据小,我们预处理素数表,然后爆搜。

    否则考虑极限数据时,(X < sqrt{10^9}),大概是 (30000),而 (Y = 10^9).

    此时,我们希望复杂度抛开 (Y),但这是不可能的。

    你会发现,你可以先求出 (leq Y) 的最大素数 (K)。由于在 (n)(2 imes n) 之间至少有一个素数,所以复杂度较低。

    你只需要考虑 (K+1) ~ (Y) 这一段,是否存在答案。

    那么,显然这个数要 (> x^2),否则肯定不如素数优。

    由于 (K)(Y) 的相差一般不超过 (10^3),此时爆搜没有问题!

    这才是真正的正解!而不是那些瞎暴力,瞎贪心的做法!

    (由于本人偷懒,觉得数据弱,因此比赛的时候就不是按照正解打的)

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    inline bool prime(int n) {
    	if(n<2) return 0;
    	for(int i=2;i*i<=n;i++)
    		if(n%i==0) return 0;
    	return 1;	
    }
    
    int main(){
    	freopen("homework.in","r",stdin);
    	freopen("homework.out","w",stdout);
    	int n=read(),m=read();
    	if(m>1e5) {
    	for(int i=m;i>=1;i--)
    		if(prime(i)) {
    			printf("%d
    ",i);
    			return 0;
    		}}
    	for(int i=m;i>=n;i--) {
    		bool f=0; int x=sqrt(i);
    		for(int j=2;j<=min(x,n);j++)
    			if(i%j==0) {f=1;break;}
    		if(!f) {printf("%d
    ",i);return 0;}
    	} puts("1"); 
    	return 0;
    }
    

    T5 pet

    水题。

    从大到小一个个抛弃就行了。

    不过我的思路比较清奇,从小到大一个个加入。

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e5+1;
    
    inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    int n,A,B;
    int a[N];
    
    inline int chu(int x,int y) {
    	return (x%y==0)?(x/y):(x/y+1);
    }
    
    int main(){
    	freopen("pet.in","r",stdin);
    	freopen("pet.out","w",stdout);
        n=read(); B=read(); A=read();
        int x=read(),ans=0;
        for(int i=1;i<n;i++) a[i]=read();
        int S=chu(x*B,A)-x;
        sort(a+1,a+n);
        for(int i=1;i<n;i++)
            if(ans+a[i]<=S) ans+=a[i];
            else {printf("%d
    ",n-i);return 0;}
        printf("%d
    ",0);    
    	return 0;
    }
    
    

    T6 fight

    水题。

    我线段树竟然炸了一次 我****

    线段树随便维护,或者差分。

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N=1e6+1;
    
    #define L i<<1
    #define R (i<<1)+1
    
    inline ll read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	ll x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    struct tree{
    	int l,r; ll tag;
    	ll sumi;
    };
    tree t[4*N];
    int n,m; ll a[N];
    
    inline void update(int i) {
    	t[i].sumi=t[L].sumi+t[R].sumi;
    }
    
    inline void pass(int i,ll x) {
    	t[i].tag+=x;
    	t[i].sumi+=x*(t[i].r-t[i].l+1);
    }
    
    inline void pushdown(int i) {
    	pass(L,t[i].tag);
    	pass(R,t[i].tag);
    	t[i].tag=0;
    }
    
    inline void build_tree(int i,int l,int r) {
    	t[i].l=l; t[i].r=r;
    	if(l==r) {
    		t[i].sumi=a[l]; t[i].tag=0;
    		return;
    	} int mid=(l+r)>>1;
    	build_tree(L,l,mid);
    	build_tree(R,mid+1,r);
    	update(i);
    }
    
    inline ll query(int i,int l,int r) {
    	if(l<=t[i].l && t[i].r<=r) return t[i].sumi;
    	int mid=(t[i].l+t[i].r)>>1; ll ans=0;
    	pushdown(i);
    	if(l<=mid) ans+=query(L,l,r);
    	if(r>mid) ans+=query(R,l,r);
    	return ans; 
    }
    
    inline void change(int i,int l,int r,int x) {
    	if(l<=t[i].l && t[i].r<=r) {
    		t[i].sumi+=x*(t[i].r-t[i].l+1);
    		t[i].tag+=x; return ;
    	} pushdown(i);
    	int mid=(t[i].l+t[i].r)>>1;
    	if(l<=mid) change(L,l,r,x);
    	if(r>mid) change(R,l,r,x);
    	update(i);
    }
    
    inline ll ask(int i,int l) {
    	if(t[i].l==l && t[i].r==l) return t[i].sumi;
    	pushdown(i); int mid=(t[i].l+t[i].r)>>1;
    	if(l<=mid) return ask(L,l);
    	else return ask(R,l);
    }
    
    int main(){
    	freopen("fight.in","r",stdin);
    	freopen("fight.out","w",stdout);
    	n=read(),m=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	build_tree(1,1,n);
    	while(m--) {
    		int l=read(),r=read(),x=read();
    		change(1,l,r,-x); 
    	} for(int i=1;i<=n;i++)
    		printf("%lld ",max(ask(1,i),0ll));
    	return 0;
    }
    

    T7 spell

    赵海鲲巨佬关于此题的见解

    这道题目爆搜要有技巧 不像我第一次乱搜才 30.

    首先是枚举全排列。请用库函数!而不是自己模拟,那样会多带来 (O(n)) 的复杂度。 不像我第一次模拟全排列

    然后,由于全排列的不重复性和上面巨佬所说,判断也非常简单 不像我第一次排序一个个查

    所以,总时间复杂度为:(O(n! imes n)).

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    int n,a[11],f[11];
    int ans=0;
    
    inline bool check() {
    	for(int i=1,s;i<=n;i++) {
    		for(int j=1;j<=i;j++) {
    			int maxi=INT_MIN,mini=INT_MAX;
    			for(int k=j;k<=i;k++) maxi=max(maxi,f[k]),mini=min(mini,f[k]);
    			if(maxi-mini==i-j) {
    				s=i-j+1; break;
    			}
    		} if(s-a[i]) return 0;
    	} return 1;
    }
    
    int main(){
    	freopen("spell.in","r",stdin);
    	freopen("spell.out","w",stdout);
    	n=read();
    	for(int i=1;i<=n;i++) a[i]=read(),f[i]=i;
    	do {
    		ans+=check();
    	} while(next_permutation(f+1,f+n+1));
    	printf("%d
    ",ans);
    	return 0;
    }
    
    

    T8 reinforce

    [赵海鲲巨佬关于此题的见解]

    由于我其它题都说的没他好,所以这题一定要详!细!说!

    算法一

    [L=n-1 ]

    这是 (20 \%) 的数据,直接输出和啊。因为你随便跳到一个地方,都可以再跳到终点。

    得分:(20pts).

    算法二

    [1 leq L < N leq 5,0 leq a_i leq 3 ]

    很显然,枚举全排列作为当前跳法即可。

    得分:(50pts).

    如果前20%和这个不重合,可以到70pts!!!

    算法三

    暴力 + 贪心。

    贪心的认为:每次跳得越远越好。

    用那个大佬的几张图。

    (L=4),此时他有两种选择。

    走近的,他就是脑抽 你会发现还是要走到那个远一些的地方。

    所以浪费了一片荷叶。(虽然本来也要浪费,但是大数据之下我们要节省)

    走远的,他就是天才 这时就跳到了终点,还尽量的节省了荷叶。

    所以,每次从起点开始暴力跳一次,并把荷叶弄掉,直到跳不过。

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e5+1;
    
    inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    int n,L,a[N];
    int ans=0;
    
    inline int go() { //跳1次
    //	for(int i=1;i<=n;i++) printf("%d ",a[i]);
    //	putchar('
    ');
    	int i=0;
    	while(i<=n) {
    //		printf("%d
    ",i);
    		if(i+L>=n) return 1;
    		bool f=0;
    		for(int j=i+L;j>i;j--)
    		    if(a[j]) {
    //		    	printf("!%d
    ",j);
    		    	f=1; i=j; a[j]--;
    		    	break;
    			}
    		if(!f) return 0;	
    	}
    }
    
    int main(){
    	freopen("reinforce.in","r",stdin);
    	freopen("reinforce.out","w",stdout);
        n=read(); L=read();
        for(int i=1;i<n;i++) a[i]=read();
        while(1) {
    	    if(go()) ans++;
    		else break;
    	} printf("%d
    ",ans);
    	return 0;
    }
    
    

    而这只能得到 (80pts).

    ???

    你想,这时间复杂度是 (O(n imes L imes a_i)).(如果每次尝试次数达到极值,会导致复杂度炸裂)

    下面考虑动态规划。

    什么?动态规划?

    哦~ 原来是个动态规划水题。

    嗯?你突然觉得不对啊?

    (O(n imes L)) 怎么过得了呢?

    谁说过不了呢?

    代码中会解释。

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e5+1;
    
    inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    int n,L,a[N];
    int f[N];
    
    int main(){
    	freopen("reinforce.in","r",stdin);
    	freopen("reinforce.out","w",stdout);
        n=read(); L=read();
        for(int i=1;i<n;i++) a[i]=read();
        memset(f,0,sizeof(f));
    	a[n]=INT_MAX; f[0]=INT_MAX;
    	for(int i=0;i<n;i++)
    	for(int j=min(i+L,n),t;j>i && f[i]>0;j--) {
    		t=min(a[j],f[i]);
    		f[j]+=t; f[i]-=t;
    		a[j]-=t;
    	} printf("%d
    ",f[n]);
    	return 0;
    }
    
    

    似乎(O(n imes L)) 啊,怎么就 (A) 了呢 ?~~?

    确实啊。???

    但是,对于 ( exttt{xyx}) 的水随机数据来说,f[i]>0 这一句,就把所有没有荷叶的剪枝了。

    那么,如果是随机数据,一半的状态就没了呀。

    你再想想,出题人是让荷叶多呢还是不让荷叶多?

    当然不让荷叶多啊,这样才能卡得了暴力,让暴力尝试最远的地方达到极值;然后在几个不多的位置堆积荷叶。

    那么,没有荷叶的已经没了,那几个位置(或许是几千个,几万个)算个啥?

    你可能觉得,什么?盲猜出题人心理也能 (A) 题?

    没错。

    再举个例子,比方说出题人让你验证一个 ([1,10^8]) 的答案,没有任何单调性,且时限是 (500ms),告诉你用老年机测。

    这时,甲乙丙三位选手都发现验证只需要 (O(1)) 的时间,然后:

    /*
    这是甲的程序
    for(int i=1;i<=100000000;i++) {
        // do sth
    }
    */
    
    /*
    这是乙的程序
    for(int i=100000000;i>=1;i--) {
        // do sth
    }
    */
    
    /*
    最后是丙的程序
    for(int i=50000000,j=50000000;i>=1;i--,j++) {
        // do sth
    }
    */
    

    最终的结果呢?甲和乙去世了,丙存活了。

    为什么呢?

    因为,出题人想要同时卡你从两边开始枚举的数据,就会让答案接近中间。

    然后,丙猜到了这一点,从中间开始枚举,然后 (A) 了。

    那你说:出题人同时出三个极限,中间,两边,不就行了?那大家得分不都一样?

    不。你不懂出题人的心理。

    出题人总是想高级的思维、算法能拿到更多的分数,而丙虽然只是一丢丢的优化,但是 感动了出题人的心 却抓住了问题的关键。

    所以呢,出题人的心理很重要。

    回到本题,ta 为了卡暴力,肯定会让你尝试荷叶的次数越来越多达到极值,所以会在不多的位置放极多个荷叶。

    而动态规划的时间复杂度与荷叶个数无关。

    然后你就巧妙的避开了荷叶个数,成功 (A) 题了。

    xyx的心理不也就这样子

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e5+1;
    
    inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    int n,L,a[N];
    int f[N];
    
    int main(){
    	freopen("reinforce.in","r",stdin);
    	freopen("reinforce.out","w",stdout);
        n=read(); L=read();
        for(int i=1;i<n;i++) a[i]=read();
        memset(f,0,sizeof(f));
    	a[n]=INT_MAX; f[0]=INT_MAX;
    	for(int i=0;i<n;i++) //朴素动态规划
    	for(int j=min(i+L,n),t;j>i && f[i]>0;j--) {
    		t=min(a[j],f[i]);
    		f[j]+=t; f[i]-=t;
    		a[j]-=t;
    	} printf("%d
    ",f[n]);
    	return 0;
    }
    
    

    后记:

    这场比赛仍然不难,抓住本质即可!

  • 相关阅读:
    sqlserver 游标格式 东师理想
    java流下载 东师理想
    列出所有K个元素的子集2013年1月26日
    你刚才在淘宝上买了一件东西【技术普及贴】(转载)
    递归统计项目中的非空白代码行数
    算法(数据结构)每天一题 2013年1月21日
    《TCP/IP详解卷1》学习小结(二)Internet Protocol
    产生所有排列字典顺序2013年1月23日
    产生所有排列旋转法2013年1月22日
    《TCP/IP详解卷1》学习小结(三)ARP协议与RARP协议
  • 原文地址:https://www.cnblogs.com/bifanwen/p/12552684.html
Copyright © 2011-2022 走看看