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;
}
相關文章
相關標籤/搜索