2018.8.19提升B组模拟考试

嗯明天要开始作A组了,由于B组全是原题...题还特别水...ios

 

T1 题意简述:jzoj3927算法

 

Description

ZPS通过长期的努力争取,终于成为了0901班的领操员,他要带领0901班参加广播操比赛。如今0901班的队伍能够看做是一个n*n的点阵,每一个人都站在格点上。如今做为领操员的ZPS站(0,0)点,他想知道若是0901班的队伍站齐了,他能看到多少我的的脸(假设每一个人的身高相同,体积相同)。

Input

一个正整数n。

Output

ZPS能看到多少我的的脸(固然他是看不到本身的脸的)。

Data Constraint

40%的数据,n<=1500。
100%的数据,n<=100000。

 

   解题思路:各位大佬有没有以为这道题很眼熟呀?ui

             没错,这道题和[SDOI2008]仪仗队如出一辙...spa

             作过的大佬能够跳过了....net

             画图观察发现答案即为sum[phi[1]~phi[n-1]]+2。code

             注意当n=1时要特判。blog

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
ll n,jdg[100001],prime[100001],phi[100001],cnt,ans;
void getphi()
{
    phi[1]=1;jdg[1]=1;
    for(ll i=2;i<=n;i++)
    {
        if(!jdg[i])
        {
            prime[++cnt]=i;
            phi[i]=i-1;
        }
        for(ll j=1;j<=cnt;j++)
        {
            if(i*prime[j]>n)
                break;
            jdg[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
}
int main()
{
    scanf("%lld",&n);
    if(n==1){printf("0\n");return 0;}
    getphi();
    for(int i=1;i<n;i++)
        ans+=phi[i];
    ans=ans*2+1;
    printf("%lld\n",ans);
}

 


 

T2 题意简述:jzoj3928排序

 

Description

有问题,找副连,无聊的时候固然也能够找他啦。小W找到了他的叔叔——东厂厂长——宇宙超级无敌老WS yy。他们叔侄两个商量以后决定用弹弓打破社区里的一些窗户,可是弹弓每秒只能完全打破一扇窗户。并且若是某户窗户的主人回来了的话,他们就不能进行破坏了(否则会死得很惨的)。由于有的人装的玻璃好,有的人装的玻璃差,有的人装的玻璃高,有的人装的玻璃矮,因此你不能要求他们叔侄两个打破不一样的窗户得到的快乐值必须相同。如今他们想知道在能活着的状况下可以得到的最大快乐值。

Input

第一行一个正整数n,表示共有n个窗户。
接下来n行,每行两个整数,第一个为窗子的主人回来的时刻(秒),第二个为破坏该窗户所能得到的快乐值。

Output

最大的快乐值。

Data Constraint

20%的数据,n<=100。
40%的数据,n<=50000。
100%的数据,n<=200000,快乐值的绝对值不超过32767,时刻非负且小于2^31。

 

   解题思路:纯贪心。队列

             把事件按时间从早到晚排序,用一个小根堆维护。事件

             若队列内元素个数小于当前事件时间,则直接加入队列。

             不然,把队列中价值最低的元素与当前事件价值对比。

             若当前事件价值较大就把堆顶弹出,压入当前事件。

             注意特判价值为负以及时间为0的状况。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
ll n,ans;
struct uio{
    ll tim,val;
}win[200001];
priority_queue<ll,vector<ll>,greater<ll> > que;
bool cmp(uio x,uio y)
{
    if(x.tim==y.tim) return x.val>y.val;
    return x.tim<y.tim;
}
int main()
{
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
        scanf("%lld%lld",&win[i].tim,&win[i].val);
    sort(win+1,win+1+n,cmp);
    for(ll i=1;i<=n;i++)
    {
        if(win[i].val<0||win[i].tim==0) continue;
        if(que.size()<win[i].tim){que.push(win[i].val);continue;}
        else if(que.top()<win[i].val){que.pop();que.push(win[i].val);continue;}
    }
    while(!que.empty())
    {
        ans+=que.top();
        que.pop();
    }
    printf("%lld\n",ans);
    return 0;
}

 


 

T3 题意简述:jzoj3929

 

Description

上帝手中有着n种被称做“世界元素”的东西,如今他要把它们中的一部分投放到一个新的空间中去以建造世界。每种世界元素均可以限制另一种世界元素,因此说上帝但愿全部被投放的世界元素都有至少一个没有被投放的世界元素可以限制它,这样上帝就能够保持对世界的控制。
因为那个著名的有关于上帝能不能制造一块连本身都不能举起的大石头的二律背反命题,咱们知道上帝不是万能的,并且不但不是万能的,他甚至有事情须要找你帮忙——上帝但愿知道他最多能够投放多少种世界元素,可是他只会O(2^n)级别的算法。虽然上帝拥有无限多的时间,可是他也是个急性子。你须要帮助上帝解决这个问题。

Input

第一行一个正整数n,表示世界元素的数目。
第二行n个正整数a_1, a_2, ..., a_n。a_i表示第i个世界元素可以限制的世界元素的编号。

Output

最多能够投放的世界元素的数目。

Data Constraint

30%的数据,n<=10。
60%的数据,n<=10^5。
100%的数据,a_i<=n<=10^6。

 

   解题思路:题解中提供了2种思路。这里介绍(懒人专属)贪心作法。

             发现题目中给的图是基环森林(树),所以能够贪心。

             相似拓扑排序,找出图中全部入度为0的点,压入队列中。

             对于一个点,查询它和它的儿子是否已经计入答案。若均未计入答案则儿子计入答案。

             查询当前点的儿子的儿子是否入度为0,如果则压入队列。

             最后会剩下一个某些点已被染色的环,按照以上策略再次贪心便可。

             另外一种作法是dp,想看这种解法的能够去PoPoQQQ大佬那里看看。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
int n,ans,son[1000001],head[1000001],d[1000001],vis[1000001];
queue<int> que;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {scanf("%d",&son[i]);d[son[i]]++;}
    for(int i=1;i<=n;i++) if(!d[i]) que.push(i);
    while(!que.empty())
    {
        int now=que.front();que.pop();
        if(!vis[now]&&!vis[son[now]])
        {
            vis[son[now]]=1,ans++;
            d[son[son[now]]]--;
            if(!d[son[son[now]]]) que.push(son[son[now]]);
        }
        vis[now]=1;
    }
    for(int i=1;i<=n;i++) if(!vis[i])
    {
        vis[i]=1;
        int tmp=son[i],cnt=1;
        while(tmp!=i) vis[tmp]=1,tmp=son[tmp],cnt++;
        ans+=cnt/2;
    }
    printf("%d\n",ans);
    return 0;
}
相关文章
相关标签/搜索