CF Educational Round 19 797 (F题DP+RMQ)以后补
来源:互联网 发布:淘宝 诚信荣誉 编辑:程序博客网 时间:2024/06/05 18:01
A题 http://codeforces.com/problemset/problem/797/A
因子分解即可,三分钟写完wa了半个小时,代码写的搓。
以此输出0.....k-2。k-1==n/已经输出的积(特判一下k==1的情况)。
#include <iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=200100;struct node{ int a; int b;}vis[maxn];int main(){ memset(vis,0,sizeof(vis)); int n,k; scanf("%d%d",&n,&k); int t=1; int sum=0; int y=n; int cnt=0; while(n>1) { ++t; if(n%t) continue; int flag=0; while(n%t==0) { n=n/t; flag++; sum++; } vis[cnt].a=t; vis[cnt].b=flag; cnt++; } if(sum<k) { printf("-1\n"); return 0;} else if(sum==k) { printf("%d",vis[0].a); vis[0].b-=1; for(int j=0;j<cnt;j++) { while(vis[j].b!=0) { printf(" %d",vis[j].a); vis[j].b--; } } printf("\n"); } else { if(k==1) { printf("%d\n",y); return 0; } int ans=1; int t=0; printf("%d",vis[0].a); vis[0].b--; t++; ans*=vis[0].a; for(int j=0;j<cnt;j++) { if(t==k-1) break; while(vis[j].b!=0) { printf(" %d",vis[j].a); t++; ans*=vis[j].a; vis[j].b--; if(t==k-1) break; } if(t==k-1) break; } if(t==k-1) {printf(" %d\n",y/ans);} else printf("\n"); } return 0;}
B http://codeforces.com/problemset/problem/797/B
把所有正整数(x)加起来(同时如果x是奇数,把-x扔到优先队列中)(别忘了有些数字开始就是负奇数也要扔到队列里),如果是奇数直接输出,偶数弹出优先队列的队列首(从大到小)相加,输出即可!
#include <iostream>#include<stdio.h>#include<algorithm>#include<queue>#include<string.h>using namespace std;const int maxn=1e5+10;priority_queue<int> fj,fo;typedef long long ll;int main(){ int n; scanf("%d",&n); ll ans=0; for(int i=0;i<n;i++) { int x; scanf("%d",&x); if(x>0) { ans+=x; if(x%2) fj.push(-x); else fo.push(-x); } else { if(x%2) fj.push(x); else fo.push(x); } } if(ans%2) printf("%I64d\n",ans); else { printf("%I64d\n",ans+fj.top()); } return 0;}
题意看了半天,就是两种操作
1. 把串s的首字母扔到t中
2. 把串t中的最后一个字母扔到u中 (不难发现串t其实就是一个栈)
aim:使u的字典序最小
做法如下
1 首先扫一遍s串把每个字母在s串中的出现次数算出来(vis数组)
2 再扫一遍
2-1.如果栈t为空把s[i]塞入栈 ,vis[s[i]-'a']--(s串中这个字母被取出);
2-2.如果栈不为空
1.此时s串中没有比栈顶的元素更小的(0(1)在vis数组找一遍),弹出栈顶,加入到u串中。
2.如果有比栈顶的更小的,把s[i]塞入栈 ,vis[s[i]-'a']--(s串中这个字母被取出);
3别忘了,当i到n的时候 栈有可能里面还有元素,以此加入u串中
4输出
#include <iostream>#include<stdio.h>#include<algorithm>#include<string.h>#include<stack>using namespace std;const int maxn=1e5+120;char s[maxn];stack<char> mys;char ans[maxn];int vis[30];int main(){ memset(vis,0,sizeof(vis)); memset(ans,0,sizeof(ans)); scanf("%s",s); int n=strlen(s); int cnt=0; int i=0; for(int i=0;i<n;i++) { vis[s[i]-'a']++; } i=0; while(i<n) { if(mys.size()==0) { mys.push(s[i]); vis[s[i]-'a']--; i++; } else { int t=mys.top()-'a'; bool tt=0; for(int j=0;j<t;j++) { if(vis[j]) tt=1; } if(tt) { mys.push(s[i]); vis[s[i]-'a']--; i++; } else { ans[cnt++]=mys.top(); mys.pop(); } } } while(mys.size()) { ans[cnt++]=mys.top(); mys.pop(); } for(int i=0;i<cnt;i++) { printf("%c",ans[i]); } printf("\n"); return 0;}
D http://codeforces.com/problemset/problem/797/D
英语渣题意迷了好久,意思就是有1-n个树的节点 (V-LSON-RSON,其中v是data值,LSON,RSON这里都是节点的下标)。这些节点会构成一个二叉搜索树(左儿子小于根,右儿子大于根)。
aim:有多少个节点存放不合适?
(注意:有的V会出现多次)
思路,
1.首先用vis[]数组把出现左右儿子的节点下标都记录一下了。再扫一遍1-n,没有做过标记的就是root。
2.开一个map<int,int>记录下来每个v出现多少次(以后算答案)
3 DFS(now,p,q) p是下界 q是上界;
DFS(root,-inf,inf) 从root开始依次找不合法的节点(这里用将合法的节点出现次数改为0来实现)
左儿子DFS(root.lson,p,min(q,now.data)) 因为左儿子要比根小
右儿子DFS(root.rson,max(p,now.data),q) 因为右儿子要比根大
(记得判断左右儿子是否存在)
4 做完DFS之后扫一遍树的节点如果map不为0,加到ans中。
(记得把map再改为0,因为后面有可能还有V避免重复)
5 输出
#include <iostream>#include<stdio.h>#include<algorithm>#include<string.h>#include<map>using namespace std;const int maxn=2e5+20;const int inf=1e9+10;struct node{ int data; int lson,rson;}tree[maxn];//记录树节点的样子bool vis[maxn];//判断那个节点的标号出现过,没有出现过的就是rootmap<int,int> myp;//记录每个节点的值出现的次数,可能一个data出现多次!void dfs(int now,int mi,int ma ){ if(now==-1) return ; if(tree[now].data>=mi&&tree[now].data<=ma) { if(myp[tree[now].data]) myp[tree[now].data]=0; } dfs(tree[now].lson,mi,min(ma,tree[now].data)); dfs(tree[now].rson,max(mi,tree[now].data),ma);}int main(){ myp.clear(); memset(vis,0,sizeof(vis)); int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d%d",&tree[i].data,&tree[i].lson,&tree[i].rson); if(tree[i].lson!=-1) vis[tree[i].lson]=1; if(tree[i].rson!=-1) vis[tree[i].rson]=1; myp[tree[i].data]++; } int root; for(int i=1;i<=n;i++) if(!vis[i]) root=i; dfs(root,-inf,inf); int ans=0; for(int i=1;i<=n;i++) { ans+=myp[tree[i].data]; myp[tree[i].data]=0; //这个很关键防止再次加上这个节点值的出现次数 } printf("%d\n",ans); return 0;}
E http://codeforces.com/problemset/problem/797/E
我的做法就是暴力模拟(当然是TLE)
看了网上的题解,大致就是
本题的入手点在于分别考虑解决问题的难点,以及巧妙地暴力。
- 在不考虑
n 的数据规模的情况下,可以根据每个查询暴力解出答案(用变量的变化模拟p 的移动)。 - 在不考虑
k 的数据规模的情况下,可以进行动态规划。令d[i][j] 表示当前起始位置为i ,k 为j 的情况下需要多少步能够走出数组,那么按照 i从大到小的顺序DP 就能得到答案d[p][k] 。
但是本题的问题在于
(大致就是k小的时候DP)
dp[j][i] j表示k ,i表示p{
=dp[j][i+a[i]+j]+1 (当i+a[i]+j<=n时候)
=1 (当i+a[i]+j>n时候)
}
代码如下
#include <iostream>#include<cstdio>#include<algorithm>#include<string.h>#include<queue>using namespace std;const int maxn=1e5+10;const int s=330;int a[maxn];int dp [s+5][maxn];int n,k,p,q;int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); memset(dp,0,sizeof(dp)); scanf("%d",&q); for(int j=1;j<=s;j++) //j 代表的是k { for(int i=n;i>=1;i--) // i是p { if(i+j+a[i]>n) dp[j][i]=1; else dp[j][i]=dp[j][i+a[i]+j]+1; } } while(q--) { int p,k; scanf("%d%d",&p,&k); if(k<=s) { printf("%d\n",dp[k][p]); continue; } else { int cnt=0; while(p<=n) { cnt++; p=p+a[p]+k; } printf("%d\n",cnt); } } return 0;}
F题 看了题解 用大佬们单调队列做+dp做的
本题的入手点在于恰当地选择解决问题的顺序,能设计动态规划算法并使用数据结构进行优化。
在不考虑任何数据规模的情况下,我们显然可以对每只老鼠考虑它们在哪个洞中,或对每个洞考虑它收容哪些老鼠。如果用那么可以用搜索将问题顺利解决。
但是显然我们不能不考虑数据规模,在本题的数据规模下,我们或许能够利用以上两种顺序中的一个,通过动态规划加以解决。为了让问题更清晰,我们似乎应该对老鼠和老鼠洞按坐标排序。
考虑让 d[i][j] 表示安排了前 i 个老鼠洞,前 j 只老鼠都得到妥善安置的最小的距离和。那么状态 (i,j) 由 (i−1,j),(i−1,j−1),……,(i−1,j−c[i]) 中 d 值最小的状态转移过来(其中 c[i] 表示第 i 个老鼠洞的容量)。于是在动态规划的同时做 RMQ 即可。
在思考实现方式的过程中要注意以下几个问题:
- 如何用数据结构优化
RMQ (单调队列)? - 如何快速得知前
j 个老鼠到第i 个洞的距离之和(预处理)? - 如何优化算法的空间复杂度(滚动数组)?
- 累加数据会不会出问题(防溢出)?
但我RMQ只会用个线段树 最多来个ST
链接:http://blog.csdn.net/liang5630/article/details/7917702
我还是太弱了!!!!!
- CF Educational Round 19 797 (F题DP+RMQ)以后补
- Educational Codeforces Round 19 F(dp+队列优化)
- CF Educational Round 23 F.MEX Queries
- Educational Codeforces Round 5 [补F]
- Codeforces 补题 Educational Round 19
- cf Educational Codeforces Round 20 F. Coprime Subsequences
- cf Educational Codeforces Round 25 F. String Compression
- Educational Codeforces Round 32【solved: 6 / 7】(F待补)
- CF Educational Codeforces Round 15(C)
- CF Round#409 Div2 E题DAG最长路+求解线性同余方程以后补
- CF Educational Round#21 G Solution:双函数DP+KMP
- Educational Codeforces Round 25 F. String Compression(kmp+dp)
- Educational Codeforces Round 26 D (dp好题)
- CF Educational Round 12, C
- CF Educational Round 12, B
- CF Educational Round 12,A
- [CF] Educational Codeforces Round 23
- cf Educational Codeforces Round 32
- AppbarLayout中Toolbar包含了子view时设置标题颜色
- 大数据串讲-从日志文件分析访问量最高的10个接口及响应访问量
- 从tcp到led
- 二叉排序树(二叉查找树)BST构造,节点插入,节点查找,节点删除(java)
- 结构化查询语言分类
- CF Educational Round 19 797 (F题DP+RMQ)以后补
- [BZOJ3185][Coci2011][DP]kamion
- JAVA中堆和栈的区别
- Android设计模式之单例模式
- ZOJ2316 Matrix Multiplication(找规律)
- 进程与进程描述符(task_struct)
- spring mvc 使用kaptcha生成验证码
- 搭建Samba服务RHCE-Day7
- 已知字母序列【d, g, e, c, f, b, o, a】,请实现一个函数针对输入的一组字符串 input[] = {"bed", "dog", "dear", "eye"},按照字母顺序排序并打印