ccf刷题记03

43 篇文章 0 订阅
25 篇文章 0 订阅

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

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值