套题T1
间隙妖怪(gap.cpp/c/pas)
题目描述:
八云紫是幻想乡的间隙妖怪。她喜欢和八云橙玩一个叫做翻转的游戏。具体规则如下,八云紫对一个长度为N字符串做M次翻转操作,每次操作给定一个X,八云紫将X到N-X之间的字符串翻转。她最喜欢的就是在做M次操作之前询问八云橙这个字符串会变成什么样。然而愚钝的橙一般是答不出来的。为了让橙不在紫妈面前丢脸,你能够帮帮她吗?
输入数据:
第一行:一个字符串(即原字符串)
第二行:一个整数M,表示有M次操作
第三行:M个整数,表示每次操作的X
输出数据:
一个字符串,表示M次操作之后的字符串。
输入样例:
abcdef
1
2
输出样例:
aedcbf
数据范围:
对于50%数据:M<=5000,字符串长度<=5000
对于100%数据:M<=200000,字符串长度<=200000
字符串处理,可以联想到用异或^来处理字符串反转
因为反转两遍相当于没转,所以得到了以下的东西QAQ
//二进制下异或不同的为1,相同的为0
//NOIP不让用这玩意儿
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 200005 using namespace std; int a[maxn],tmp,m; char s[maxn],ans[maxn]; int main() { freopen("gap.in","r",stdin); freopen("gap.out","w",stdout); scanf("%s%d",s+1,&m); int n=strlen(s+1); for(int i=1;i<=m;++i) { scanf("%d",&tmp); a[tmp]^=1; a[n-tmp+2]^=1; } tmp=0; for(int i=1;i<=n;++i) { tmp^=a[i]; if(tmp) ans[i]=s[n-i+1]; else ans[i]=s[i]; } ans[n+1]='\0'; cout<<ans+1; puts(""); fclose(stdin);fclose(stdout); return 0; }
正解
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define inf 0x3f3f3f3f using namespace std; int len,n,a[300005]; //n<1 ??? char s[300005],p[300005]; int main(){ freopen("gap.in","r",stdin);freopen("gap.out","w",stdout); scanf("%s",s+1); len=strlen(s+1); scanf("%d",&n); for(int i=1;i<=len;i++)p[i]=s[i]; for(int i=1;i<=n;i++){ int x; scanf("%d",&x); x=min(x,len-x+1); a[x]++; } int q=0; for(int i=1;i<=len/2+1;i++){ q+=a[i]; if(q%2==0){ s[i]=p[i]; s[len-i+1]=p[len-i+1]; } else{ s[i]=p[len-i+1]; s[len-i+1]=p[i]; } } for(int i=1;i<=len;i++)printf("%c",s[i]); printf("\n"); fclose(stdin); fclose(stdout); return 0; }
数据控制(loading.c/cpp/pas)
题目描述:
UUZsama为了控制妖梦的网速,专门设置了一个数据监控系统。这个系统的工作原理是这样的:每隔一段时间检查一次,如果网速超过限定速度,则掐断网络。得知这件事情的妖梦为了赶紧把新的电影下载完,就使用了一个奇怪的东西来解决这个事情,这个东西的特点是:每一秒,妖梦都可以使得当前网速增加或者减小,但是增加/减小的范围不能超过Limit(设变动前网速是v,则变动后网速Vt的范围是max(0,V-limit) <= Vt <= V+Limit )。现在知道第T秒的时候UUZ就要开始查网络了,为了保证以后还会有网络用,妖梦必须保证在第T秒的时候自己的网速是小于等于限定网速的。请问妖梦从现在到UUZ检查结束这段时间内最多能下载的电影的大小是多少?
输入描述:
第一行:两个整数,Vs,Vd 。 Vs表示当前网络速度,Vd表示UUZ的网络限定速度(单位均为MB/s)。
第二行:两个整数T,Limit。T表示第T秒的时候检查网络,Limit表示网速变动的最大值。
输出描述:
一个数字,表示UUZ检查结束后妖梦最多下的电影的大小(单位是MB)
样例输入:
5 6
4 2
样例输出:
26
样例解释:
第一秒:速度为5 MB/s,总大小为5MB
第二秒:速度为7 MB/s,总大小为12MB
第三秒:速度为8 MB/s,总大小为20MB
第四秒:速度为6 MB/s,总大小为26MB
幻想乡的网速是很快的哟!但是速度什么的都是整数的啊。
数据范围:
0 <= Vs,Vd <= 100
2 <= t <= 100
0 <= d <= 10
不知道为什么一开始一直觉得这个是dp……卡了好久
正解是贪心啦QAQ
在所有T时刻都<=Vd,在T-1就是能达到的最大的Vd+Limit,T-i就是能达到的最大的Vd+Limit*i,能达到的最大的Vd+Limit*i
满足递归的定义:从当前 到下一个时间最大的下载量就是这个区域的下载量;
这个就是转化成了很多个子问题,从下个时间到下下个时间,还是一个初始速度,到T为止每一段都是一样的。
有两种可能的情况:
①全加速也达不到Vd —>一直加速就行
②是要+然后- —>对于每一个T-i,Vnowmax=Vd+Limit*i
然后一个个推就资磁了
Vnow=min( Vs+j*Limt, Vd+i*Limit )
//k为当前点 m为起点 j=k-m, i= T-k
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int vs,vd,limit,t; int ans=0; int vnow; int main() { freopen("loading.in","r",stdin); freopen("loading.out","w",stdout); cin>>vs>>vd>>t>>limit; for(int i=1;i<=t;++i) { /* if(vnow+limit<=vd) { vnow+=limit; ans+=vnow; } else { */ int j=i-1,k=t-i; vnow=min(vs+j*limit,vd+k*limit); ans=vnow+ans; // cout<<vnow<<" "; // } } cout<<ans; puts(""); fclose(stdin);fclose(stdout); return 0; }
没有人双色球(ball.cpp/c/pas)
题目背景:
Nizilia原是一个国家的公主,小时候的她非常喜欢和国王的近臣Kating玩一种名字叫做双色球的游戏。有一天,Kating发动了叛乱,Nizilia被囚禁起来,看着父亲死在自己的面前,Nizilia心如刀绞,在度日如年的囚禁生活中,Nizilia靠破译一个锁来度日,只有打开这个锁,才有可能逃出去。。。。。。
题目描述:
这个锁的结构是一个栈。
这个栈内初始有n个红色和蓝色的小球,Nizilia需要按照以下规则进行操作:
- 只要栈顶的小球是红色的,将其取出,直到栈顶的球是蓝色
- 然后将栈顶的蓝球变成红色
- 最后放入若干个蓝球直到栈中的球数为n
以上3步骤为一次操作
如栈中都是红色球,则操作停止,请问最少几次操作后停止
输入格式:
第一行为一个整数n,表示栈的容量为n
第二行为一个字符串,第i个字符表示自顶向下的第i个球的颜色,R代表红色,B代表蓝色
输出格式:
一个整数表示操作数
样例输入:
样例1:
3
RBR
样例2:
4
RBBR
样例输出:
样例1:2
样例2:6
数据范围:
50%数据:n<=20
100数据:n<=50
总觉得这题似曾相识然而还是爆炸了
注意是自顶向下呀!样例给的是对称的不要过了就不测了QAQ
还有操作次数可能非常大于是要long long来记录
一轮三次(不满三次也算一次)才算一次操作
然后剩下的就是模拟了QAQ
有一种大概会T的非正解
还有另一种二进制的做法QAQ
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<stack> using namespace std; int n,qiushu,hongqiu=0; long long ans=0; char a[55]; stack<char>QAQ; int main() { freopen("ball.in","r",stdin); freopen("ball.out","w",stdout); scanf("%d%s",&n,a+1); qiushu=n; for(int i=n;i>=1;--i) { QAQ.push(a[i]); if(a[i]=='R')hongqiu++; } while(n) { if(hongqiu==n)break; while (QAQ.top()=='R') { QAQ.pop(); qiushu--; hongqiu--; } if(QAQ.top()=='B') { QAQ.pop(); QAQ.push('R'); hongqiu++; } if(qiushu<n) { for(int i=qiushu;i<n;++i) { QAQ.push('B'); qiushu++; } } ans++; } cout<<ans; puts(""); fclose(stdin);fclose(stdout); return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 200005 using namespace std; int main() { freopen("ball.in","r",stdin); freopen("ball.out","w",stdout); int n; char a[55]; scanf("%d%s",&n,a); int pow=1; long long sum=0; for (int i=0;i<n;++i) { if (a[i]=='B')sum+=pow; pow<<=1; } printf("%d",sum); puts(""); fclose(stdin);fclose(stdout); return 0; }
正解是数学问题QAQ
//是根据小数据推出来的结论不是公理
弱弱的DXY
题目描述
DXY太弱了,以至于他已经不知道要如何解决调整一个数列的使得他变成一个严格上升序列。
输入格式
第 1 行,1 个整数 N
第 2 行,N 个整数 A1,A2,...,AN
输出格式
1 个整数,表示最少需要修改的多少个数字,使得数列变成单调上升的序列。
样例输入
3
1 3 2
样例输出
1
数据:
对于50%的数据:N<=1000
对于100%的数据:N<=100000
保证所有输入整数<=2^63-1
由于数据比较弱所以可以直接写成最长上升子序列然后n-f[n]骗骗分(大雾)
正解的话是把位置i上的数字减去i,做不下降子序列就好了,不过普通dp会T要找nlogn的做法QAQ
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define LiangJiaJun main #define INF 1999122700 using namespace std; int a[100004]; int unset[100004],n; int cnt=0; int erfen(int x){ int l=0,r=n,ans=0; while(l<=r){ int mid = (l+r) >> 1; if(unset[mid]>x)r=mid-1; else{ ans = mid; l = mid + 1; } } return ans; } int LiangJiaJun(){ freopen("loser.in","r",stdin);freopen("loser.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); a[i]-=i; } for(int i=0;i<=n+1;i++)unset[i]=INF; unset[1]=a[1];unset[0]=-INF; for(int i=2;i<=n;i++){ int x=erfen(a[i])+1; unset[x]=min(a[i],unset[x]); } for(int i=1;i<=n;i++)if(unset[i]!=INF)cnt=i; cout<<n-cnt<<endl; fclose(stdin);fclose(stdout); return 0; }