https://cn.vjudge.net/contest/234044#overview
总体而言一部分傻逼题一部分难题
A.
傻逼题1
拿stack模拟一下即可。
#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
int main()
{
int n,i,j,k;
string str1,str2;
while(cin>>n){
cin>>str1>>str2;reverse(str2.begin(),str2.end());
vector<int>ans;
stack<int>sta1,sta2;
for(i=0;i<str2.size();i++)sta2.push(str2[i]);
for(i=0;i<str1.size();i++){
ans.push_back(1);sta1.push(str1[i]);
while(!sta1.empty()&&sta1.top()==sta2.top())
sta1.pop(),sta2.pop(),ans.push_back(2);
}
if(!sta1.empty()){
puts("No.");
}
else{
puts("Yes.");
for(i=0;i<ans.size();i++)
if(ans[i]==1)
puts("in");
else puts("out");
}
puts("FINISH");
}
return 0;
}
B.HDU1023
裸的卡特兰数,不知道的话这题可以弃疗了(比如像本蒟蒻,摔
要么打表,网上有卡特兰数的表,要么递推求,int128是水不过去的,老老实实写高精吧,或者赶紧学一波java(摔
#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 1000;
struct bign{
int d[maxn], len;
void clean() { while(len > 1 && !d[len-1]) len--; }
bign() { memset(d, 0, sizeof(d)); len = 1; }
bign(int num) { *this = num; }
bign(char* num) { *this = num; }
bign operator = (const char* num){
memset(d, 0, sizeof(d)); len = strlen(num);
for(int i = 0; i < len; i++) d[i] = num[len-1-i] - '0';
clean();
return *this;
}
bign operator = (int num){
char s[20]; sprintf(s, "%d", num);
*this = s;
return *this;
}
bign operator + (const bign& b){
bign c = *this; int i;
for (i = 0; i < b.len; i++){
c.d[i] += b.d[i];
if (c.d[i] > 9) c.d[i]%=10, c.d[i+1]++;
}
while (c.d[i] > 9) c.d[i++]%=10, c.d[i]++;
c.len = max(len, b.len);
if (c.d[i] && c.len <= i) c.len = i+1;
return c;
}
bign operator - (const bign& b){
bign c = *this; int i;
for (i = 0; i < b.len; i++){
c.d[i] -= b.d[i];
if (c.d[i] < 0) c.d[i]+=10, c.d[i+1]--;
}
while (c.d[i] < 0) c.d[i++]+=10, c.d[i]--;
c.clean();
return c;
}
bign operator * (const bign& b)const{
int i, j; bign c; c.len = len + b.len;
for(j = 0; j < b.len; j++) for(i = 0; i < len; i++)
c.d[i+j] += d[i] * b.d[j];
for(i = 0; i < c.len-1; i++)
c.d[i+1] += c.d[i]/10, c.d[i] %= 10;
c.clean();
return c;
}
bign operator / (const bign& b){
int i, j;
bign c = *this, a = 0;
for (i = len - 1; i >= 0; i--)
{
a = a*10 + d[i];
for (j = 0; j < 10; j++) if (a < b*(j+1)) break;
c.d[i] = j;
a = a - b*j;
}
c.clean();
return c;
}
bign operator % (const bign& b){
int i, j;
bign a = 0;
for (i = len - 1; i >= 0; i--)
{
a = a*10 + d[i];
for (j = 0; j < 10; j++) if (a < b*(j+1)) break;
a = a - b*j;
}
return a;
}
bign operator += (const bign& b){
*this = *this + b;
return *this;
}
bool operator <(const bign& b) const{
if(len != b.len) return len < b.len;
for(int i = len-1; i >= 0; i--)
if(d[i] != b.d[i]) return d[i] < b.d[i];
return false;
}
bool operator >(const bign& b) const{return b < *this;}
bool operator<=(const bign& b) const{return !(b < *this);}
bool operator>=(const bign& b) const{return !(*this < b);}
bool operator!=(const bign& b) const{return b < *this || *this < b;}
bool operator==(const bign& b) const{return !(b < *this) && !(b > *this);}
string str() const{
char s[maxn]={};
for(int i = 0; i < len; i++) s[len-1-i] = d[i]+'0';
return s;
}
};
istream& operator >> (istream& in, bign& x)
{
string s;
in >> s;
x = s.c_str();
return in;
}
ostream& operator << (ostream& out, const bign& x)
{
out << x.str();
return out;
}
int main()
{
bign a[105],mul,chu;
a[1]=1;
int i,j,n;
for(i=2;i<=100;i++) {
mul=(4 * i - 2);chu=(i + 1);
a[i] = a[i - 1] * mul / chu;
}
while(cin>>n){
cout<<a[n]<<endl;
}
return 0;
}
C.
写着让用queue没看出跟queue啥关系,写了一发spfa
(好吧,听说是想让你bfs,这时候就会用到队列…)
#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
struct edge{
int to,cost;
};
int main()
{
int n,a,b,s,i,j,k;
while(cin>>n&&n) {
cin>>a>>b;
vector<edge>G[205];
bool inque[205]={0};
int dis[205];memset(dis,0x3f,sizeof(dis));
//for (i = 1; i <= n; i++)dis[i] = (1 << 31) - 1;
dis[a] = 0;
for (i = 1; i <= n; i++) {
cin>>j;
if(i+j<=n)G[i].push_back(edge{i+j,1});
if(i-j>0)G[i].push_back(edge{i-j,1});
}
queue<int> que;
que.push(a);
//inque[s] = true;
while (!que.empty()) {
int t = que.front();
que.pop();
inque[t] = false;
for (i = 0; i < G[t].size(); i++) {
edge e = G[t][i];
if (dis[e.to] > dis[t] + e.cost) {
dis[e.to] = dis[t] + e.cost;
if (!inque[e.to]) {
que.push(e.to);
inque[e.to] = true;
}
}
}
}
if(dis[b]==0x3f3f3f3f)
puts("-1");
else cout<<dis[b]<<endl;
}
return 0;
}
D.
智商检测题
#include<cstdio>
#include<iostream>
#include<string>
#include<map>
using namespace std;
int main()
{
int n,i,j,k;
while(cin>>n&&n){
string str;map<string,int>mp;
while(n--){
cin>>str;mp[str]++;
}
map<string,int>::iterator iter;
int maxn=0;string ans;
for(iter=mp.begin();iter!=mp.end();iter++){
if(iter->second>maxn){
maxn=iter->second;ans=iter->first;
}
}
cout<<ans<<endl;
}
return 0;
}
E.
稍复杂的智商检测,map里面嵌套map
#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
int main()
{
int n,i,j,k;
cin>>n;
for(i=1;i<=n;i++){
typedef map<string,map<string,int> > Map;
Map mp;
int m;cin>>m;
for(j=1;j<=m;j++){
string str1,str2;int a;cin>>str1>>str2>>a;
mp[str2][str1]+=a;
}
Map::iterator iter;map<string,int>::iterator iter1;
for(iter=mp.begin();iter!=mp.end();iter++){
cout<<iter->first<<endl;
for(iter1=iter->second.begin();iter1!=iter->second.end();iter1++){
cout<<" |----"<<iter1->first<<'('<<iter1->second<<')'<<endl;
}
}
if(i!=n)puts("");
}
return 0;
}
F.HDU 4302
好多做法都能水过去,写了个multiset+模拟,题目本身不难但是若干小细节需要注意,容易写挂
#include<cstdio>
#include<iostream>
#include<set>
#include<algorithm>
#include<cmath>
using namespace std;
int main()
{
int T,i,j,k,cnt=0;
cin>>T;
while(T--){
cnt++;
multiset<int>s;multiset<int>::iterator iter,iter1;
int pos=0,dir=1,len=0;
int l,n;cin>>l>>n;
while(n--){
scanf("%d",&i);
if(!i) {
scanf("%d", &j);
s.insert(j);
//for(auto a:s)cout<<a<<' ';cout<<endl;
}
else{
if(s.empty())continue;//没蛋糕的时候原地不动
//cout<<pos<<endl;
iter=s.lower_bound(pos);//找最近的蛋糕
if(iter==s.end()){
iter--;
dir=0;len+=abs(pos-(*iter));pos=(*iter);s.erase(iter);
}
else if(iter==s.begin()){
len+=abs(pos-(*iter));pos=(*iter);dir=1;s.erase(iter);
}
else{//如果被两块蛋糕夹在中间,需要讨论
iter1=--iter;iter++;
if(abs(pos-(*iter1))<abs(pos-(*iter))){//如果一侧距离更短
dir=0;len+=abs(pos-(*iter1));pos=(*iter1);s.erase(iter1);
}
else{
if(abs(pos-(*iter1))==abs(pos-(*iter))){//如果距离相等,看方向
if(dir==0){
len+=abs(pos-(*iter1));pos=(*iter1);
if((*iter1)<pos)dir=0;s.erase(iter1);
}
else{
if((*iter)>pos)dir=1;
len+=abs(pos-(*iter));pos=(*iter);s.erase(iter);
}
}
else{//距离不等
if((*iter)>pos)dir=1;
len+=abs(pos-(*iter));pos=(*iter);s.erase(iter);
}
}
}
}
}
printf("Case %d: %d\n",cnt,len);
}
return 0;
}
G.HDU 6109
这道题有两个关系,相等关系和不等关系,相等关系有传递性,这个很容易想到并查集这个数据结构来表示这个关系,然后是不等关系,这个因为没有传递关系,所以不能用并查集来表示。这道题一开始我想到的是挑战程序设计书上的食物链那道题,想要用unite(a,b+MAXN),unite(a+MAXN,b)来表示不等关系,这种方法是错的,这种方法是当a,b表示不在同一集合,并且集合种类只有两个的时候才是这样做法。 原因是,那道题中两个元素如果不是相等,那么肯定就是反面,也就是一个元素可以跟另一个元素的反面合并。而在这题中,如果对于a,b,c有a!=b,b!=c,那么把a,c合并到一起肯定是有问题的。
可以考虑用set来记录不等,当a!=b的时候,给a的set压入b,给b的set压入a,这样当询问a和某个数是否有不相等关系的时候,查一查a的set里面有没有这个数。
考虑set的方法和并查集结合起来,当a和b合在同一个集合s中的时候,如果把a的set和b的set的信息都添加到s的set里面。考虑以下这种情况,a!=c,b!=d,a==b,那么c和b是肯定不相等的,当a和b合并集合的时候,按上面说的那种想法,那么此时find(b)的set里面一查就有c这个数了,这样就能判断出c这个数不等于b了。具体的实现是在并查集的find函数里面加一个pushup函数,类似与线段树的pushup,把儿子的信息合并到父亲身上,这种时间复杂度因为并查集的路径压缩可以很小。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<set>
#include<cstring>
#include<vector>
using namespace std;
const int N=1e5+5;
int par[N];
set<int>s[N];int cnt;
void init(void)
{
for(int i=1;i<N;i++)
par[i]=i,s[i].clear();
cnt=0;
}
void pushup(int x,int fa)//路径压缩的时候把这个点的所有不等信息合并到他的祖先那里去
{
s[fa].insert(s[x].begin(),s[x].end());
}
int find(int x)
{
if(x==par[x])
return x;
pushup(x,par[x]);//信息上推
return par[x]=find(par[x]);
}
void unite(int x,int y)
{
x=find(x),y=find(y);
if(x==y)return;
if(s[x].size()<s[y].size())//优化,类似按秩合并
par[x]=y;
else {
par[y]=x;
}
}
int main()
{
int l,i,j,e,k;
vector<int>ans;
cin>>l;init();
while(l--){
cnt++;
scanf("%d%d%d",&i,&j,&e);
i=find(i);j=find(j);//注意一定要把find的值赋值给原数
if(!e){
if(i==j){
ans.push_back(cnt);
init();
continue;
}
s[i].insert(j);s[j].insert(i);
}
else{
if(s[i].count(j)||s[j].count(i)){
ans.push_back(cnt);
init();continue;
}
unite(i,j);
}
}
cout<<ans.size()<<endl;
for(i=0;i<ans.size();i++)
cout<<ans[i]<<endl;
return 0;
}
H,I本蒟蒻暂时不会,flag在此。
J. POJ 3275
题目要求的是最少需要知道多少关系能够保证100%知道剩下所有关系的情况,因此我们应该尽量多的根据已有条件推断牛之间的关系,而剩下的情况从最糟糕的角度看,应该是每一对关系都需要问询一次才能得知。
而为了推断已有关系,可以类比有向图最短路来做,利用floyd。但是朴素的floyd O(n^3)的复杂度太高了,所以要用邻接表优化一下。
#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
int main()
{
int n,m,i,j,k;
bool issure[1005][1005]={0};
vector<int>from[1005],to[1005];
cin>>n>>m;
for(i=1;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
from[x].push_back(y);to[y].push_back(x);issure[x][y]=true;//比x小的关系,比y大的关系
}
for(k=1;k<=n;k++)
for(i=0;i<to[k].size();i++)
for(j=0;j<from[k].size();j++){
int u,v;
u=to[k][i],v=from[k][j];//k是用来松弛的点,注意字母顺序!!
if(!issure[u][v]) {//注意字母顺序!!
issure[u][v] = true;from[u].push_back(v);to[v].push_back(u);
}
}
int res=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
if (i == j)continue;
if (issure[i][j])
res++;
}
cout<<n*(n-1)/2-res<<endl;
return 0;
}
K. Hiho 1513
一个蛮神奇的bitset的应用,当然,其实也可能是因为我自己本来就不大会bitset,所以看起来挺神奇的。
思路:首先设法将每门科目的排名列出,开一个二维的bitset数组,根据每门科目的排名利用&运算,求出所有科目都比当前人名次靠前的同学的人数。
大致思想就是,对于每个人的每一科,预处理出这一科比他高的人,并在代表那个人的编号的位上记为1 ,然后对于每个人,把他5科排名的bitset &起来,就可以得到所有科都比他高的人的数目了
#include<cstdio>
#include<iostream>
#include<cstring>
#include<bitset>
#include<algorithm>
using namespace std;
const int N=3e4+5;
bitset<N>high[5][N],ans;//high表示第j科排名第i的人前面的名次的位置
int mark1[5][N],stu[5][N];//mark记录第j科排名第i的人的编号,stu表示第j科编号为i的人的名次
int main()
{
int n,i,j,k;
cin>>n;
for(i=1;i<=n;i++)
for(j=0;j<5;j++){
int t;scanf("%d",&t);
mark1[j][t]=i;stu[j][i]=t;
}
for(j=0;j<5;j++)
for(i=1;i<=n;i++){
if(i==1)high[j][i]=0;
else{
high[j][i]=high[j][i-1];
high[j][i].set(mark1[j][i-1]);
}
}
for(i=1;i<=n;i++){
ans=high[0][stu[0][i]];
for(j=1;j<5;j++)
ans&=high[j][stu[j][i]];
cout<<ans.count()<<endl;
}
return 0;
}

这篇博客主要介绍了在2018年春季训练中遇到的一些编程题目,涉及到使用STL和算法解决各种问题。其中包括使用stack模拟、卡特兰数的递推与高精度计算、并查集和队列的应用、智商检测题以及使用bitset和多集合优化的Floyd算法。作者还分享了在解决不等关系问题时的思考过程,以及如何结合set和并查集的数据结构来解决问题。
133

被折叠的 条评论
为什么被折叠?



