P3951 小凯的疑惑
题目描述
小凯手中有两种面值的金币,两种面值均为正整数且彼此互素。每种金币小凯都有 无数个。在不找零的情况下,仅凭这两种金币,有些物品他是无法准确支付的。现在小 凯想知道在无法准确支付的物品中,最贵的价值是多少金币?注意:输入数据保证存在 小凯无法准确支付的商品。
输入输出格式
输入格式:
两个正整数 aa 和 bb ,它们之间用一个空格隔开,表示小凯中金币的面值。
输出格式:
一个正整数 NN ,表示不找零的情况下,小凯用手中的金币不能准确支付的最贵的物品的价值。
输入输出样例
3 7
11
说明
【输入输出样例 1 说明】
小凯手中有面值为 33 和 77 的金币无数个,在不找零的前提下无法准确支付价值为 1, 2,4,5,8,111,2,4,5,8,11 的物品,其中最贵的物品价值为 1111 ,比 1111 贵的物品都能买到,比如:
题解:a*b-a-b
P3952 时间复杂度
题目描述
小明正在学习一种新的编程语言 A++,刚学会循环语句的他激动地写了好多程序并 给出了他自己算出的时间复杂度,可他的编程老师实在不想一个一个检查小明的程序, 于是你的机会来啦!下面请你编写程序来判断小明对他的每个程序给出的时间复杂度是否正确。
A++语言的循环结构如下:
F i x y
循环体
E
其中F i x y
表示新建变量 ii (变量 ii 不可与未被销毁的变量重名)并初始化为 xx , 然后判断 ii 和 yy 的大小关系,若 ii 小于等于 yy 则进入循环,否则不进入。每次循环结束后 ii 都会被修改成 i +1i+1 ,一旦 ii 大于 yy 终止循环。
xx 和 yy 可以是正整数( xx 和 yy 的大小关系不定)或变量 nn 。 nn 是一个表示数据规模的变量,在时间复杂度计算中需保留该变量而不能将其视为常数,该数远大于 100100 。
“E”表示循环体结束。循环体结束时,这个循环体新建的变量也被销毁。
注:本题中为了书写方便,在描述复杂度时,使用大写英文字母“O”表示通常意义下“Θ”的概念。
输入输出格式
输入格式:
输入文件第一行一个正整数 tt ,表示有 tt ( t \le 10t≤10 )个程序需要计算时间复杂度。 每个程序我们只需抽取其中 F i x y
和E
即可计算时间复杂度。注意:循环结构 允许嵌套。
接下来每个程序的第一行包含一个正整数 LL 和一个字符串, LL 代表程序行数,字符 串表示这个程序的复杂度,O(1)
表示常数复杂度,O(n^w)
表示复杂度为 n^wnw ,其 中w是一个小于100的正整数(输入中不包含引号),输入保证复杂度只有O(1)
和O(n^w)
两种类型。
接下来 LL 行代表程序中循环结构中的F i x y
或者 E
。 程序行若以F
开头,表示进入一个循环,之后有空格分离的三个字符(串)i x y
, 其中 ii 是一个小写字母(保证不为 nn ),表示新建的变量名, xx 和 yy 可能是正整数或 nn ,已知若为正整数则一定小于 100。
程序行若以E
开头,则表示循环体结束。
输出格式:
输出文件共 tt 行,对应输入的 tt 个程序,每行输出Yes
或No
或者ERR
(输出中不包含引号),若程序实际复杂度与输入给出的复杂度一致则输出Yes
,不一致则输出No
,若程序有语法错误(其中语法错误只有: ① F 和 E 不匹配 ②新建的变量与已经存在但未被销毁的变量重复两种情况),则输出ERR
。
注意:即使在程序不会执行的循环体中出现了语法错误也会编译错误,要输出 ERR
。
输入输出样例
8 2 O(1) F i 1 1 E 2 O(n^1) F x 1 n E 1 O(1) F x 1 n 4 O(n^2) F x 5 n F y 10 n E E 4 O(n^2) F x 9 n E F y 2 n E 4 O(n^1) F x 9 n F y n 4 E E 4 O(1) F y n 4 F x 9 n E E 4 O(n^2) F x 1 n F x 1 10 E E
Yes Yes ERR Yes No Yes Yes ERR
说明
【输入输出样例解释1】
第一个程序 ii 从 1 到 1 是常数复杂度。
第二个程序 xx 从 1 到 nn 是 nn 的一次方的复杂度。
第三个程序有一个 F
开启循环却没有 E
结束,语法错误。
第四个程序二重循环, nn 的平方的复杂度。
第五个程序两个一重循环, nn 的一次方的复杂度。
第六个程序第一重循环正常,但第二重循环开始即终止(因为 nn 远大于100,100大于4)。
第七个程序第一重循环无法进入,故为常数复杂度。
第八个程序第二重循环中的变量 xx 与第一重循环中的变量重复,出现语法错误②,输出 ERR
。
【数据规模与约定】
对于 30\%30% 的数据:不存在语法错误,数据保证小明给出的每个程序的前 L/2 行一定为以 F
开头的语句,第L/2+1 行至第 LL 行一定为以 EE 开头的语句, L≤10 ,若 x、y 均 为整数, xx 一定小于 yy ,且只有 yy有可能为 nn 。
对于 50\%50% 的数据:不存在语法错误,L≤100 ,且若 x 、 yy均为整数, xx一定小于 y , 且只有 y 有可能为 n 。
对于 70\%70% 的数据:不存在语法错误,L≤100 。
对于 100\%100% 的数据:L≤100 。
题解:大模拟,括号,栈
#include#include <string> #include #include #include #include using namespace std; struct node{ int Complex,Flag; char var; }; int main(){ int t,n; cin>>t; while(t--){ int cmp,cur_Com=0,max_Com=0,idx=1,Flag=0; bool vis[30]; memset(vis,0,sizeof(vis)); stack st; string s,c1,c2,c3,c4; cin>>n>>s; if(s[2]=='1') cmp=0; else sscanf(s.c_str(),"O(n^%d)",&cmp); for(int i=1;i<=n;i++){ cin>>c1; if(c1[0]=='F'){ cin>>c2>>c3>>c4; if(!idx) continue; if(vis[c2[0]-'a']){idx=0;continue;} vis[c2[0]-'a']=1; st.push((node){cur_Com,Flag,c2[0]}); if(Flag) Flag=1; else if(c3[0]=='n'&&c4[0]!='n') Flag=1; else if(c3[0]!='n'&&c4[0]!='n'){ int cc3=atoi(c3.c_str()); int cc4=atoi(c4.c_str()); if(cc3>cc4) Flag=1; } else if(c3[0]!='n'&&c4[0]=='n'){ cur_Com++; max_Com=max(max_Com,cur_Com); } } else if(c1[0]=='E'){ if(!idx) continue; if(st.empty()) {idx=0;continue;} node tmp=st.top();st.pop(); cur_Com=tmp.Complex; vis[tmp.var-'a']=0; Flag=tmp.Flag; } } if(!idx||!st.empty()) cout<<"ERR"<<endl; else{ if(max_Com==cmp) cout<<"Yes"<<endl; else cout<<"No"<<endl; } } return 0; }
P3960 列队
题目描述
Sylvia
是一个热爱学习的女♂孩子。
前段时间,Sylvia
参加了学校的军训。众所周知,军训的时候需要站方阵。
Sylvia 所在的方阵中有 n \times mn×m 名学生,方阵的行数为 nn ,列数为 mm 。
为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中 的学生从 1 到 n \times mn×m 编上了号码(参见后面的样例)。即:初始时,第 ii 行第 jj 列 的学生的编号是 (i-1)\times m + j(i−1)×m+j 。
然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队。在一天 中,一共发生了 qq 件这样的离队事件。每一次离队事件可以用数对 (x,y) (1 \le x \le n, 1 \le y \le m)(x,y)(1≤x≤n,1≤y≤m) 描述,表示第 xx 行第 yy 列的学生离队。
在有学生离队后,队伍中出现了一个空位。为了队伍的整齐,教官会依次下达 这样的两条指令:
-
向左看齐。这时第一列保持不动,所有学生向左填补空缺。不难发现在这条 指令之后,空位在第 xx 行第 mm 列。
-
向前看齐。这时第一行保持不动,所有学生向前填补空缺。不难发现在这条 指令之后,空位在第 nn 行第 mm 列。
教官规定不能有两个或更多学生同时离队。即在前一个离队的学生归队之后, 下一个学生才能离队。因此在每一个离队的学生要归队时,队伍中有且仅有第 nn 行 第 mm 列一个空位,这时这个学生会自然地填补到这个位置。
因为站方阵真的很无聊,所以 Sylvia
想要计算每一次离队事件中,离队的同学 的编号是多少。
注意:每一个同学的编号不会随着离队事件的发生而改变,在发生离队事件后 方阵中同学的编号可能是乱序的。
输入输出格式
输入格式:
输入共 q+1q+1 行。
第 1 行包含 3 个用空格分隔的正整数 n, m, qn,m,q ,表示方阵大小是 nn 行 mm 列,一共发 生了 qq 次事件。
接下来 qq 行按照事件发生顺序描述了 qq 件事件。每一行是两个整数 x, yx,y ,用一个空 格分隔,表示这个离队事件中离队的学生当时排在第 xx 行第 yy 列。
输出格式:
按照事件输入的顺序,每一个事件输出一行一个整数,表示这个离队事件中离队学 生的编号。
输入输出样例
2 2 3 1 1 2 2 1 2
1 1 4
说明
【输入输出样例 1 说明】
列队的过程如上图所示,每一行描述了一个事件。 在第一个事件中,编号为 11 的同学离队,这时空位在第一行第一列。接着所有同学 向左标齐,这时编号为 22 的同学向左移动一步,空位移动到第一行第二列。然后所有同 学向上标齐,这时编号为 44 的同学向上一步,这时空位移动到第二行第二列。最后编号 为 11 的同学返回填补到空位中。
【数据规模与约定】
数据保证每一个事件满足1≤x≤n,1≤y≤m
题解:https://www.luogu.org/blog/ztzshiwo001219/solution-p3960
#includeusing namespace std; const int inf = 1000000008, maxn = 300005; int w; #define ll long long vector a[maxn]; void read(int &x){ int f=1;x=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} x*=f; } struct Node { int v; Node *ls, *rs; void up(){ v = ls->v + rs->v; } }pool[maxn*50], *tail = pool, * root[maxn], *zero; void build(){ zero = ++tail; zero->ls = zero->rs = zero; zero->v = 0; } Node * newnode(){ Node *nd = ++tail;//要有++tail nd->v = 0; nd->ls = nd->rs = zero; return nd; } int query(Node *nd, int pos, int lf = 1, int rg = w){ if(lf == rg)return lf; if(nd == zero)nd = newnode(); if(nd->ls == zero)nd->ls = newnode(); if(nd->rs == zero)nd->rs = newnode(); int mid = (lf + rg) >> 1; int t = mid - lf + 1 - nd->ls->v; if(pos <= t)return query(nd->ls, pos, lf, mid); else return query(nd->rs, pos-t, mid+1, rg); } void modify(Node *nd, int pos, int lf = 1, int rg = w){ if(nd == zero)nd = newnode(); if(lf == rg){nd->v = 1;return;} if(nd->ls == zero)nd->ls = newnode(); if(nd->rs == zero)nd->rs = newnode(); int mid = (lf + rg) >> 1; if(pos <= mid)modify(nd->ls, pos, lf, mid); else modify(nd->rs, pos, mid+1, rg); nd->up(); } int main() { //freopen("phalanx.in","r",stdin); //freopen("phalanx.out","w",stdout); int n, m, q; scanf("%d%d%d",&n, &m, &q); w = max(n, m) + q + 1; build(); for(int i = 1; i <= n+1; i++)root[i] = newnode(); while(q--){ int x, y, z; ll ans; read(x), read(y); if(y != m){ z = query(root[x], y); if(z < m)ans = 1ll* (x - 1) * m + z; else ans = a[x][z - m]; printf("%lld\n",ans); modify(root[x], z); a[n + 1].push_back(ans); z = query(root[n + 1], x); //id[x][y] have been deleted //printf("%lld %d\n",ans, z); if(z <= n)ans =1ll* m * z; else ans = a[n + 1][z - n - 1]; a[x].push_back(ans); modify(root[n + 1], z); // printf("%lld %d\n",ans, z); } if(y == m){ int z = query(root[n + 1], x); if(z <= n)ans =1ll* m * z; else ans = a[n + 1][z - n - 1]; printf("%lld\n",ans); modify(root[n + 1], z); a[n + 1].push_back(ans); // printf("%lld %d\n",ans, z); } } return 0; }