T1:卡片(card)
【题目描述】
lrb喜欢玩卡牌。他手上现在有张牌,每张牌的颜色为红绿蓝中的一种。现在他有两种操作。一是可以将两张任意位置的不同色的牌换成一张第三种颜色的牌;二是可以将任意位置的两张相同颜色的牌换成一张该颜色的牌。两个操作后都可以将生成的牌放到任意位置。现在他想知道,最后一张牌可能是什么颜色的。
【输入描述】
第一行输入一个,表示卡牌数量。
第二行输入一个由’B’,’G’,’R’组成的长度为的字符串,分别表示卡牌的颜色为蓝色、绿色、红色中的一种。
【输出描述】
输出’B’,’G’,’R’中的若干个字母,按字典序输出。代表可能的最后一张牌的颜色。
【样例】
输入1 |
输出1 |
2 RB |
G |
输入2 |
输出2 |
3 GRG |
BR |
输入3 |
输出3 |
4 BBBB |
B |
【数据范围】
对于100%的数据,n<=200
——————————————————我是分割线————————————————————
这是一道简单分析题。(入门难度。。不要吐槽)
很显然我们发现如果3张牌都超过一张,三种情况都会出现(BGR)
那么如果有2张牌都超过2张,同上
剩下3种情况:
1,1,0(数字表示牌的数量)那么答案就是牌数是0的那张
2,1,0(2表示2张以上)那么答案就是牌数为1和0的两张
1,0,0(1表示一张以上)那么答案就是牌数为1的那一张
然后。。。做完了
下面贴上代码
#include<cstdio> using namespace std; int a[4],n; int er,yi,sa; char ch; char ans[3]={'B','G','R'}; void swap(int &a,int &b){a^=b;b^=a;a^=b;} int main(){ freopen("card.in","r",stdin); freopen("card.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++){ ch=getchar(); while(ch<'A'||ch>'Z')ch=getchar(); if(ch=='B')a[1]++; else if(ch=='G')a[2]++; else if(ch=='R')a[3]++; } for(int i=1;i<=3;i++)if(a[i]>=2)er++; for(int i=1;i<=3;i++)if(a[i]>=1)yi++; if(er>=2||yi==3)puts("BGR"); else if(er==1&&yi==2){ int x,y; for(int i=1;i<=3;i++)if(a[i]==0)x=i;else if(a[i]==1)y=i; if(x>y)swap(x,y); printf("%c%c ",ans[x-1],ans[y-1]); }else if(yi==2){ int x; for(int i=1;i<=3;i++)if(!a[i])x=i; printf("%c ",ans[x-1]); }else if(yi==1){ int x; for(int i=1;i<=3;i++)if(a[i])x=i; printf("%c ",ans[x-1]); } fclose(stdin); fclose(stdout); }
————————————————我是分割线——————————————————
T2:取数(win)
【题目描述】
lrb目前有个数字,他想知道这个数中选出若干个数,平均数减中位数的最大值是多少。可以证明,对于一个递增数列,如果是平均数减中位数最大时的中位数,表示在两边分别取相邻数字的数量,表示以为中位数,在两侧各取相邻个数时平均数减中位数的值,那么为关于的单峰函数。
【输入描述】
第一行为,为数字个数。
第二行有个数,分别代表个数字。
【输出描述】
输出一个数,为平均数减中位数的最大值,保留两位小数。
【样例】
输入 |
输出 |
4 1 2 3 4 |
0.33 |
【数据范围】
对于60%的数据,n<=21
对于75%的数据,n<=1000
对于100%的数据,n<=10^5,0<=ai<=10^6
——————————————————我是分割线————————————————————
这题首先我们要想到的就是枚举中位数。
那么假设我们已知某一个数是中位数,那么我们怎么求最优的答案呢?
对于一个已经排序过的数列,
显然我们要在这个中位数的左边和右边同时取相同数量的数。
对于中位数的左边,显然越靠近中位数的数越优,
对于中位数的右边,越远离中位数的数越优。
所以对于第i个数作为中位数的情况,我们左边从第i-1位开始向左取数,右边从第n位开始向左取数。而取数的个数自然就是三分啦!(三分的过程用前缀和O(1)求平均数)
至于为什么偶数个数的数列不是最优解,这个我留个坑以后来填。
下面贴代码(当然我写了偶数版本)
#include<cstdio> #include<algorithm> #define MN 100005 using namespace std; int a[MN],n; long long sum[MN]; double ans=-100000000; int main(){ freopen("win.in","r",stdin); freopen("win.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); sort(a+1,a+n+1); int l=0,r=0,lm=0,rm=0,le=0; double la=a[1],ra=a[1]; for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i]; for(int i=1;i<=n;i++){ le=min(i-1,n-i); le=max(le,0); l=0,r=le; while(l<r-1){ lm=l+(r-l)/3,rm=r-(r-l)/3; la=(double)(sum[i-1]-sum[i-1-lm]+sum[n]-sum[n-lm]+a[i])/(double)(2*lm+1); ra=(double)(sum[i-1]-sum[i-1-rm]+sum[n]-sum[n-rm]+a[i])/(double)(2*rm+1); if(la<ra)l=lm+1; else r=rm-1; } la=(double)(sum[i-1]-sum[i-1-l]+sum[n]-sum[n-l]+a[i])/(double)(2*l+1); ra=(double)(sum[i-1]-sum[i-1-r]+sum[n]-sum[n-r]+a[i])/(double)(2*r+1); if(la<ra)ans=max(ans,ra-(double)a[i]); else ans=max(ans,la-(double)a[i]); } la=ra=(double)(a[1]+a[2])/2.0; for(int i=1;i<n;i++){ le=min(i-1,n-i-1); le=max(le,0); l=0,r=le; while(l<r-1){ lm=l+(r-l)/3,rm=r-(r-l)/3; la=(double)(sum[i-1]-sum[i-1-lm]+sum[n]-sum[n-lm]+a[i]+a[i+1])/(double)(2*lm+2); ra=(double)(sum[i-1]-sum[i-1-rm]+sum[n]-sum[n-rm]+a[i]+a[i+1])/(double)(2*rm+2); if(la<ra)l=lm+1; else r=rm-1; } la=(double)(sum[i-1]-sum[i-1-l]+sum[n]-sum[n-l]+a[i]+a[i+1])/(double)(2*l+2); ra=(double)(sum[i-1]-sum[i-1-r]+sum[n]-sum[n-r]+a[i]+a[i+1])/(double)(2*r+2); if(la<ra)ans=max(ans,ra-(double)((double)(a[i]+a[i+1])/(double)2)); else ans=max(ans,la-(double)((double)(a[i]+a[i+1])/(double)2)); } printf("%.2lf ",ans); fclose(stdin); fclose(stdout); }
————————————————我是分割线————————————————
T3:密码(key)
【题目描述】
lrb去柜员机取钱,并输入了他的四位密码。但是这一切都被一个黑帮拍摄了下来。幸好,这一次他的银行卡里并没有剩余任何钱。lrb知道了他的账户被异常登录后十分害怕,然后修改了他的密码。从此以后他为了不被看出密码,他开始“徐晃”。但这一切还是被拍摄了下来,拍摄多次以后,这个黑帮找到了你,希望你在一秒内帮他算出lrb的可能使用的密码数量。
【输入描述】
第一行输入一个,为lrb被拍摄的动作次数。
接下来行,每行第一个数为,表示lrb接下来的手指移动次数,接下来为一个长度为的数字串,表示lrb手指经过的轨迹。lrb手指经过的位置,可能没有按,也有可能按了多次。
【输出描述】
输出一行,为可能的密码数量。
【样例】
输入 |
输出 |
2 3 123 3 234 |
5 |
解释 |
|
lrb可能用的是2222,2223,2233,2333,3333五种密码 |
【数据范围】
设所有轨迹串的总长度为。
对于35%的数据,L<5000
对于100%的数据,1<=n<=1000,1<=t<=10^4,L<=10^6
——————————————————我是分割线——————————————————
这道题有一个简单思路(想不到的都是脑子抽了,比如我)
我们只要枚举所有的密码就好了
然后就是如何在O(n)时间内check一个密码
我们只要开一个数组记录从每一位开始,后面的第一个0-9分别在第几位,如果都能够找到,那么密码合法。
下面贴代码
#include<cstdio> #define MN 1005 #define M 1000005 #define F(x,l,r) for(int x=l;x<=r;x++) using namespace std; char e[M];int f[M][10],ans,n,t[MN]; int main(){ freopen("key.in","r",stdin); freopen("key.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d%s",&t[i],e+t[i-1]),t[i]+=t[i-1]; for(int i=0;i<=9;i++)f[t[n]][i]=t[n]; for(int i=t[n]-1;i>=0;i--){for(int j=0;j<=9;j++)f[i][j]=f[i+1][j];f[i][e[i]-'0']=i;} F(a,0,9) F(b,0,9) F(c,0,9) F(d,0,9){ int tot=0; F(i,0,n-1)if(f[f[f[f[t[i]][a]][b]][c]][d]<t[i+1])tot++; ans+=tot==n; } printf("%d ",ans); }