2017
今年9月份的最新题,还是有必要做一下的,然而网上搜不到题解,就比较坑了,没事,没做出来的题等下次ccf之前再补吧,看这段时间自己又能长进多少
201709-1打酱油
思路:这题一开始看到还有点懵,但这个样例的说明也太给了了吧,直接把做法就给出来说,分类讨论,瞬间秒做;
其实根据数据范围完全可以模拟的,单为了锻炼自己的计算能力,还是推了一下公式,这个能力还是需要的,毕竟之后无论什么题目似乎如果能用公式都比模拟好
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>
using namespace std;
a
const int maxn = 1e5+10;
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int sum = 0;
/*while(n>=50)
{
n -= 50;
sum += 7;
}*/
int p1 = n/50;
n %= 50;
sum += p1*7;
/*while(n>=30)
{
n -= 30;
sum += 4;
}*/
int p2 = n/30;
n %= 30;
sum += p2*4;
/*while(n>=10)
{
n -= 10;
sum += 1;
}*/
int p3 = n/10;
sum += p3;
printf("%d\n",sum);
}
return 0;
}
201709-2公共钥匙盒
思路:这题给的是每个老师的上课时间,拆分转化为钥匙交接的记录,按时间进行模拟就好了,建立数据结构存储时间,然后注意一下排序的原则就好了
最后,注意一下,不仅需要数组记录每个位置的钥匙,还需要单开一个数组记录钥匙的位置便于跟踪,其他就没什么了,30min2题,还好
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>
using namespace std;
const int maxn = 2010;
typedef struct EVENT
{
bool borrow;
int id;
int time;
}Event;
Event e[maxn];
int key[maxn];
int keypos[maxn];
bool cmp(const Event &a, const Event &b)
{
if(a.time<b.time)
{
return true;
}
else if(a.time==b.time)
{
if((!a.borrow)&&b.borrow)
{
return true;
}
else if((!a.borrow)&&(!b.borrow))
{
if(a.id<b.id)
{
return true;
}
}
}
return false;
}
int main()
{
int n,k;
while(scanf("%d%d",&n,&k)!=EOF)
{
for(int i=1;i<=n;i++)
{
key[i] = i;
keypos[i] = i;
}
for(int i=0;i<k;i++)
{
int keyid,keytime,keylast;
scanf("%d%d%d",&keyid,&keytime,&keylast);
e[2*i].borrow = true;
e[2*i].id = keyid;
e[2*i].time = keytime;
e[2*i+1].borrow = false;
e[2*i+1].id = keyid;
e[2*i+1].time = keytime+keylast;
}
sort(e,e+2*k,cmp);
for(int i=0;i<2*k;i++)
{
if(e[i].borrow)
{
key[keypos[e[i].id]] = 0;
keypos[e[i].id] = 0;
}
else
{
for(int pos=1;pos<=n;pos++)
{
if(key[pos]==0)
{
key[pos] = e[i].id;
keypos[e[i].id] = pos;
break;
}
}
}
}
printf("%d",key[1]);
for(int i=2;i<=n;i++)
{
printf(" %d",key[i]);
}
printf("\n");
}
return 0;
}
201709-3JSON查询
思路:这题完全是字符串处理问题,用惯了scanf和字符串数组的我,对cin和getline真心手足无措,研究了好长时间
不过,这题确实信息量有点大,而且入手点也特别多,像冒号,引号,逗号都可以作为处理对象,而且后来发现任意处理一个结果都是一样的
但刚碰到的时候,就会思路一片混乱,不易冷静
有时候,一步步慢慢检查要比一起写完反而不知道哪里错了要好,不过还是细心吧,不出错总归是好的
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>
using namespace std;
const int maxn = 1e5+10;
map<string,string> json;
bool iskey;
string dealstring(string key,string s)
{
if(s.empty())
{
//cout << "empty " << endl;
return key;
}
int slen = s.size();
for(int i=0;i<slen;i++)
{
//cout << key <<"*"<<s[i]<<"*"<<iskey<< endl;
if(s[i] == ' ')
{
continue;
}
if(s[i] == '{')
{
//cout << "*3*" << endl;
json[key] = "OBJECT";
iskey = true;
}
else if(s[i] == '}')
{
int len = key.size();
int str;
for(str = len-1;str>=0;str--)
{
if(key[str] == '.')
{
break;
}
}
if(str < 0)
{
key = "";
}
else
{
key = key.substr(0,str);
}
}
else if(s[i] == ',')
{
iskey = true;
}
else if(s[i] == ':')
{
iskey = false;
}
else if(s[i] == '"')
{
//cout << s[i] << s[i+1]<< endl;
string nowstring;
bool di = false;
int j;
for(j=i+1;j<slen;j++)
{
if(s[j] == '\\')
{
if(di)
{
di = false;
nowstring += '\\';
}
else
{
di = true;
}
}
else if(s[j] == '"')
{
if(di)
{
di = false;
nowstring += '"';
}
else
{
break;
}
}
else
{
nowstring += s[j];
}
}
if(iskey)
{
if(key=="")
{
key = nowstring;
}
else
{
key += '.' + nowstring;
}
}
else
{
//cout << key << "*" << endl;
json[key] = "STRING " + nowstring;
int len = key.size();
int str;
for(str = len-1;str>=0;str--)
{
if(key[str] == '.')
{
break;
}
}
if(str < 0)
{
key = "";
}
else
{
key = key.substr(0,str);
}
}
i = j;
}
}
return key;
}
int main()
{
int n,m;
//cout << json["hello"] << "***" << endl;
/*if(json["hello"]=="")
{
cout << "***" << endl;
}*/
ios::sync_with_stdio(false);
while(cin >> n >> m)
{
/*char hh;
hh = getchar();
cout << "^"<<hh << endl;*/
string temp;
getline(cin,temp);
json.clear();
/*cin.clear();
cin.sync();*/
iskey = false;
string laststring = "";
while(n--)
{
getline(cin,temp);
//cout << n << "###" <<temp<< endl;
laststring = dealstring(laststring,temp);
}
while(m--)
{
//cout << m << "***" << endl;
getline(cin,temp);
if(json[temp] == "")
{
cout << "NOTEXIST" << endl;
}
else
{
cout << json[temp] << endl;
}
}
}
return 0;
}
/*
10 5
{
"firstName": "John",
"lastName": "Smith",
"address": {
"streetAddress": "2ndStreet",
"city": "NewYork",
"state": "NY"
},
"esc\\aped": "\"hello\""
}
firstName
address
address.city
address.postal
esc\aped
*/
201709-4通信网络
思路:这一题乍一看,似乎不怎么困难,统计前驱和后继,对于每个点,其前驱的前驱必是其前驱,其后继的后继必是其后继,为了去重,用两个set处理吧
果然TLE了,虽然报的是WA,但根据时间发现应该是TLE的问题,只得到了可怜的30分
然而突然发现有向图set的速度似乎有点慢,而且双向边似乎要存两遍,处理两遍
于是,考虑退化,用最基础的数组存储,果然变快了,又过了一部分数据,得到50分了
于是,又想到数组和vector结合可以避免set,然而还是50分
然后似乎就真心没什么办法了,就50分吧,以后看看能不能拿满
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>
#include <set>
using namespace std;
const int maxn = 1010;
/*set <int> pre[maxn];
set <int> nex[maxn];
set <int> connect[maxn];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++)
{
connect[i].clear();
nex[i].clear();
pre[i].clear();
connect[i].insert(i);
pre[i].insert(i);
nex[i].insert(i);
}
while(m--)
{
int p,q;
scanf("%d%d",&p,&q);
set<int> :: iterator it;
for(it=pre[p].begin();it!=pre[p].end();it++)
{
pre[q].insert(*it);
nex[*it].insert(q);
connect[q].insert(*it);
connect[*it].insert(q);
}
for(it=nex[q].begin();it!=nex[q].end();it++)
{
nex[p].insert(*it);
pre[*it].insert(p);
connect[p].insert(*it);
connect[*it].insert(p);
}
}
int sum = 0;
for(int i=1;i<=n;i++)
{
if((int)(connect[i].size())==n)
{
sum++;
}
}
printf("%d\n",sum);
}
return 0;
}*/
/*
bool connect[maxn][maxn];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(connect,false,sizeof(connect));
for(int i=1;i<=n;i++)
{
connect[i][i] = true;
}
while(m--)
{
int p,q;
scanf("%d%d",&p,&q);
for(int i=1;i<=n;i++)
{
if(connect[i][p])
{
connect[i][q] = true;
}
if(connect[q][i])
{
connect[p][i] = true;
}
}
}
int sum = 0;
for(int i=1;i<=n;i++)
{
int tempsum = 0;
for(int j=1;j<=n;j++)
{
if(connect[i][j]||connect[j][i])
{
tempsum++;
}
}
if(tempsum == n)
{
sum++;
}
}
printf("%d\n",sum);
}
return 0;
}
*/
vector <int> pre[maxn];
vector <int> nex[maxn];
bool connect[maxn][maxn];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(connect,false,sizeof(connect));
for(int i=1;i<=n;i++)
{
connect[i][i] = true;
nex[i].clear();
pre[i].clear();
pre[i].push_back(i);
nex[i].push_back(i);
}
while(m--)
{
int p,q;
scanf("%d%d",&p,&q);
vector<int> :: iterator it;
for(it=pre[p].begin();it!=pre[p].end();it++)
{
if(!connect[*it][q])
{
connect[*it][q] = true;
pre[q].push_back(*it);
nex[*it].push_back(q);
}
}
for(it=nex[q].begin();it!=nex[q].end();it++)
{
if(!connect[p][*it])
{
connect[p][*it] = true;
nex[p].push_back(*it);
pre[*it].push_back(p);
}
}
}
int sum = 0;
for(int i=1;i<=n;i++)
{
int tempsum = 0;
for(int j=1;j<=n;j++)
{
if(connect[i][j]||connect[j][i])
{
tempsum++;
}
}
if(tempsum == n)
{
sum++;
}
}
printf("%d\n",sum);
}
return 0;
}
201709-5 除法
思路:最后一题,线段树题,然而我对于线段树还是比较茫然的,还是试试骗分吧
开始了骗分之路,首先,强行模拟吧,利用第一个条件l=r,由区间变单点
后来发现只是操作1区间变单点,于是改用树状数组
然而还是0分,猛然发现,结果可能超long long,于是20分到手
于是,想再做个遍历,说不定又能骗一点分呢
果然,50分到手,最终ccf400+,还行,看来有些时候,还是变换形态吧,加油,fighting
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>
using namespace std;
const int maxn = 1e5+10;
long long a[maxn],c[maxn];
int lowbit(int x)//对应管辖区域
{
return x&-x;
}
long long sum(int i)//求数组c前i项和
{
long long s=0;
while(i>0)
{
s+=c[i];
i-=lowbit(i);
}
return s;
}
void modify(int i,long long val,int n)//将第i个元素加上val,n为数组大小
{
while(i<=n)
{
c[i]+=val;
i+=lowbit(i);
}
}
int main()
{
//cout<<"1"<<endl;
//cout<<"2"<<endl;
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
modify(i,a[i],n);
}
while(m--)
{
int p;
scanf("%d",&p);
if(p==1)
{
int l,r;
long long v;
scanf("%d%d%lld",&l,&r,&v);
//cout << l << "*"<< r << "*" << v << endl;
for(int i=l;i<=r;i++)
{
//cout << "###" << endl;
if(a[i]%v==0)
{
a[i] /= v;
long long di = a[i] - a[i]*v;
modify(i,di,n);
}
/*for(int j=1;j<=n;j++)
{
cout << sum(j) << " ";
}
cout << endl;*/
}
}
else
{
int l,r;
scanf("%d%d",&l,&r);
printf("%lld\n",sum(r) - sum(l-1));
/*for(int i=1;i<=n;i++)
{
cout << sum(i) << " ";
}
cout << endl;*/
}
}
}
return 0;
}
最后两题,这段时间确实是没时间再补了,以后有时间再看看
是时候补上陈年旧题了
根据评论区的提示,通信网络可以根据dfs水过去,一算复杂度O(n^3)感觉会凉,一交,果然凉了
不过突然想到,dfs的邻接表法可以降复杂度到O(n+m),再乘一个点数O(n),复杂度O(mn)~1e7稳了
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>
using namespace std;
const int maxn = 1e3+10;
//bool to[maxn][maxn];
vector <int> to[maxn];
vector <int> from[maxn];
bool in1[maxn],in2[maxn];
int n;
void dfs1(int k)
{
in1[k] = true;
int len = to[k].size();
for(int i=0;i<len;i++)
{
int ne = to[k][i];
if(!in1[ne])
dfs1(ne);
}
}
void dfs2(int k)
{
in2[k] = true;
int len = from[k].size();
for(int i=0;i<len;i++)
{
int ne = from[k][i];
if(!in2[ne])
dfs2(ne);
}
}
int main()
{
int m,re = 0;
scanf("%d%d",&n,&m);
//memset(to,false,sizeof to);
for(int i=1;i<=n;i++) to[i].clear(), from[i].clear();
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
to[a].push_back(b);
from[b].push_back(a);
}
for(int i=1;i<=n;i++)
{
memset(in1,false,sizeof(in1));
memset(in2,false,sizeof(in2));
int sum = 0;
dfs1(i);
dfs2(i);
for(int j=1;j<=n;j++)
if(in1[j]||in2[j])
sum++;
if(sum == n) re++;
}
printf("%d\n",re);
}
/*
1.dfs(60)
2.邻接链表
*/
最后一题,考虑到除法的速降性,其实完全不会造成超大数据的情况,一切皆在树状数组可控范围内,强行剪枝就好了
首先,剪掉被除数为0和除数为1的情况,该情况对结果完全不会造成影响
之后就是利用或这种简单运算屏蔽取模这种复杂运算,以及边scanf为cin这种玄学操作了,最终100,蔚为惊喜
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>
using namespace std;
const int maxn = 1e5+10;
long long a[maxn],c[maxn];
int lowbit(int x)//对应管辖区域
{
return x&-x;
}
long long sum(int i)//求数组c前i项和
{
long long s=0;
while(i>0)
{
s+=c[i];
i-=lowbit(i);
}
return s;
}
void modify(int i,long long val,int n)//将第i个元素加上val,n为数组大小
{
while(i<=n)
{
c[i]+=val;
i+=lowbit(i);
}
}
int main()
{
int n,m;
ios::sync_with_stdio(false);
cin >> n >>m;
//while(scanf("%d%d",&n,&m)!=EOF)
{
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)
{
cin >> a[i];
//scanf("%lld",&a[i]);
modify(i,a[i],n);
}
//sort(a,a+n);
while(m--)
{
int p;
cin >> p;
//scanf("%d",&p);
if(p==1)
{
int l,r;
long long v;
cin >> l >> r >> v;
//scanf("%d%d%lld",&l,&r,&v);
//cout << l << "*"<< r << "*" << v << endl;
if(v==1) continue;
for(int i=l;i<=r;i++)
{
//cout << "###" << endl;
if(a[i]>=v&&a[i]%v==0)
{
a[i] /= v;
long long di = a[i] - a[i]*v;
modify(i,di,n);
}
/*for(int j=1;j<=n;j++)
{
cout << sum(j) << " ";
}
cout << endl;*/
}
}
else
{
int l,r;
cin >> l >> r;
//scanf("%d%d",&l,&r);
cout << sum(r) - sum(l-1) << endl;
//printf("%lld\n",sum(r) - sum(l-1));
/*for(int i=1;i<=n;i++)
{
cout << sum(i) << " ";
}
cout << endl;*/
}
}
}
return 0;
}
/*
优化1,将除以1的直接略去(50)
优化2:排序,将大数略去(0)
优化3:将0直接略去(80)
优化4:优化取模运算(90)
优化5:scanf改为cin(100)
*/
最后鸣谢评论区的友情支持
文章地址:http://blog.csdn.net/owen_q/article/details/78229956