2020 6 7 普轉提


千年難得一見,我居然沒翻車???
awa

成功進入了rank3,然鵝。。。

 

 

 前8名全是前3。。。
妙不可言awa
只要拿到了基礎分的200,就是前3awa
哦對了,T4是原本的T1。。
T1是原本的T2,T2是原本的T3,T3是原本的T4
老師昨天題目加錯了。。。
所以就一大群人A了T4 awa
快樂

 

 

T1

睿爸喜歡搭塔塔。

睿爸有h2個高度為n1的紅色磚塊,和n2個高度為h2的藍色磚塊,這些的磚塊的底面和頂面的長寬均相同,且你不能將這些磚塊立體旋轉或者轉動。

睿爸可以按照如下方式搭塔:

1.每個磚塊要么可以放在地面上,要么必須壘在一個顏色不同的磚塊上面(一個磚塊上面僅可以放一個磚塊)。

2.至少需要一個磚塊,不必用完所有的磚塊。

睿爸想知道這樣最多可以搭出多少個不同高度的塔。

給出n1,n2,h1,h2
簡單題,但是要long,long

直接給結論,隨便推一推就好了

 

#include <bits/stdc++.h>
#define ll long long
using namespace std ;
ll a,b,x,y,ans;
inline ll read()
{
    register ll Q=0,f=1;register char C=getchar() ;
    while(C<'0'or C>'9')f=C=='-'?-1:1,C=getchar() ;
    while(C<='9'and C>='0')Q=(Q<<1)+(Q<<3)+C-'0',C=getchar() ;
    return f*Q;
}
int main()
{
    freopen("tower.in","r",stdin);
    freopen("tower.out","w",stdout);
    a=read();x=read();
    b=read();y=read();
    if(a>b)
    {
        swap(a,b);
    }
    if(x==y)
    {
        ans+=a*2;
    }
    else
    {
        ans+=a*3;
    }
    if(a!=b)ans++;
    cout<<ans<<endl;
    return 0;
}

 

T2

 

 題目的意思非常的補坑描述,我看了5分鍾才看懂。。。
就是要你在一個字符串里面在找出一個子序列(不用連續,但是要求順序不能倒)
取出以后,原本的序列要求變成取出的序列的一個排列,就是有且僅有取出的序列的全部字符
原本吧,如果真的是只有我說的這些要求,那就是一道簡單題.
如果把題目里面的字典序最小去掉,我分分鍾就能A了它,可惜去不得
顯然,子序列T的合法要求就是,在原序列S中,每個字符出現的次數必須是T中出現的次數的兩倍,否則一定不合法。
所以要如果不要保證字典序最小,這題就講完了。。。

awa

其實后面也不難搞,只用按位貪心一下,每一位都要貪心的選出能夠保證后面合法的,且字典序最小的方案。
因為字典序本身就是一種貪心。。。
如果是判斷一個字母是否合法,只需要判斷前面字母使用的次數和用完以后還有幾個剩余,就是正解了

awa

#include <bits/stdc++.h>
#define ll long long
using namespace std ;
inline ll read()
{
    register int Q=0,f=1;register char C=getchar() ;
    while(C<'0'or C>'9')f=C=='-'?-1:1,C=getchar() ;
    while(C<='9'and C>='0')Q=(Q<<1)+(Q<<3)+C-'0',C=getchar() ;
    return f*Q;
}
int s[27],ss[27],ans[27][210],m=0,n;
char ch[210];
void cherk()
{
    for(int i=0;i<26;ss[i]=s[i],i++)
    {
        if(s[i]%2!=0)
        {
            puts("Clbtxdy!");
            exit(0);
        }
    }
}
void work()
{
    for(int i=1;i<=n;i++)
    {
        int mx=0;
        for(int j=i;j<=n;j++)
        {
            int x=ch[j]-'a';
            bool ff=0;
            for(int k=0;k<26;k++)
            {
                if(x==k)
                {
                    if(ans[k][j]>s[k]/2+1)
                    {
                        ff=1;
                        break;
                    }
                }
                else
                {
                    if(ans[k][j]>s[k]/2)
                    {
                        ff=1;
                        break;
                    }
                }
            }
            if(!ff && ss[ch[j]-'a']>0)
            {
                if(mx==0)
                {
                    mx=j;
                }
                else
                {
                    if(ch[j]-'a'<ch[mx]-'a')
                    {
                        mx=j;
                    }
                }
            }
        }
        if(mx==0) mx=i;
        cout<<ch[mx];
        ss[ch[mx]-'a']-=2;
        s[ch[mx]-'a']+=2;
        m++;
        if(m==n/2)
        {
            exit(0);
        }
        i=mx;
    }
}
int main()
{
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
    scanf("%s",ch+1);
    n=strlen(ch+1);
    for(int i=1;i<=n;i++)
    {
        s[ch[i]-'a']++;
        for(int j=0;j<26;j++)
        {
            if(ch[i]-'a'!=j)
            {
                ans[j][i]=ans[j][i-1];
            }
            else
            {
                ans[j][i]=ans[j][i-1]+1;
            }
        }
    }
    cherk();
    work();
    return 0;
}

T3

是個博弈論

 

 這個問題,有一個很麻煩的地方,就是如果是個dp的話,它的狀態會十分的復雜,因為我要同時去考慮兩種狀態:1.睿爸的。2.杜教的。
但是考慮到我們最后的答案,其實要求的就是杜教扣了睿爸多少,所以就可以把睿爸取到的數先全部都加上(包括杜教的),然后再減去全部的數(只有杜教的),這就是答案。

 

其中的A是睿爸能取到的數。
U是全集
所以我們要做的事情其實就是最大化a[i]+b[i]。
那就很好搞啦!

但是這個並沒有到達博弈論的部分。
其實根本就是個貪心。。。
這只是為了方便去計算我們的答案罷了

 

現在問題已經被簡化了,我們來討論一下博弈(貪心)的策略。
因為答案和棧中的元素有關,而棧也是只有兩個元素,所以這不就是在叫着:“討論我!討論我!”嗎。。。
對於一個棧的價值,其實就是如我們上面說的,a[i]+b[i]。這個就是為什么先推出來上面的式子。
這個讓我們討論價值這件事情變得可能。

結論1:如果一個棧的價值a+b<=c+d,先手永遠只能拿到上面的,而后手總能拿到下面的。
證明1:如果先手拿了一個棧頂,那么后手一定是可以直接拿棧底的
那如果他沒拿呢?

那先手就是憨。
因為沒拿,就說明了另一個棧頂的元素肯定是要比這個棧底大的。根據我們的前提條件,先手拿的棧頂的元素是比棧頂小的。
拿為什么先手不拿這個棧頂呢?它不香嗎?

證畢。
awa

於是我們就快樂的排除掉了a+b<=c+d的棧。因為他們的貢獻是十分顯然的。

接下來考慮一下a+b>c+d的棧。

結論2:對於a+b>c+d的棧,肯定是先后手交替拿取目前最大的元素

證明2:
因為前面證明了最優的策略就是使拿到的元素兩個值相加起來最大。
所以我們肯定是要先拿取最大是元素的。
因為全部的棧都已經是a+b>c+d了,所以不會存在沖突的情況。
這樣就好了啊awa

ac!awa

#include <bits/stdc++.h>
#define ll long long
using namespace std ;
ll a[200001],b[200001],c[200001],d[200001],n;bool vis[200001];
ll ans1,ans2;
inline ll read()
{
    register ll Q=0,f=1;register char C=getchar() ;
    while(C<'0'or C>'9')f=C=='-'?-1:1,C=getchar() ;
    while(C<='9'and C>='0')Q=(Q<<1)+(Q<<3)+C-'0',C=getchar() ;
    return f*Q;
}
int main()
{
    freopen("dortmund.in","r",stdin);
    freopen("dortmund.out","w",stdout);
    n=read();
    for(ll i=1;i<=n;i++)
    {
        a[i]=read();b[i]=read();
        c[i]=read();d[i]=read();
    }
    for(ll i=1;i<=n;i++)
    {
        if(a[i]+b[i]<=c[i]+d[i])
        {
            ans1+=a[i]+b[i];
        }
    }
    priority_queue<pair<ll,ll> > q;
    for(ll i=1;i<=n;i++)
    {
        if(a[i]+b[i]>c[i]+d[i])
        {
            q.push(make_pair((a[i]+b[i]),i));
        }
    }
    ll awsd=1;
    while(q.size()!=0)
    {
//        cout<<1<<endl; 
        pair<ll,ll> x=q.top();
        ll now=x.first;
        if(awsd==1)
        {
            ans1+=now;
            awsd=2;
        }
        else
        {
            awsd=1;
        }
        if(vis[x.second]==false)
        {
            q.push(make_pair((c[x.second]+d[x.second]),x.second));
            vis[x.second]=true;
        }
        q.pop();
    }
    for(ll i=1;i<=n;i++)
    {
        ans1-=b[i];
        ans1-=d[i];
    }
    cout<<ans1<<endl;
    return 0;
}

 

 

呼~總算是寫完了awa

 

T4

 

 

 

 

 

 一看就是圖論題(逃
一看就是最短路awa
這個嘛。。。
不就是最短路和dp的結合題嗎。。。
很典型啊。。。
最短路嘛,是有狀態的,所以像這總多了一個限制條件的問題,我想應該是能夠用加一維狀態的辦法來解決的。
啥不行就給啥加狀態awa(逃
其實總是加狀態也是不行的,因為時空間復雜度撐不住啊awa
還是要看情況的awa

這個題解我是真的看不懂。。。

 

 直接放上來吧。。。
說的我好迷啊awa
淦,原來是我沒寫過幾道分層圖的dp。。。

我說為什么我最短路配dp總是不會寫。。。

不寫了,補坑去了awa

代碼用了機房dalao lsf的神奇dfs,跑的比正解還快,而且好寫。。。
本質就是一個朴素的dfs。。。。
code

#include <bits/stdc++.h>
#define ll long long
using namespace std;
struct edge
{
    ll to,next,v;bool f; 
}e[10001];
ll head[10001],tot,n,m,k;bool vis[10001],vis2[10001];int dis[1001][20],ans=INT_MAX;
inline ll read()
{
    register ll Q=0,f=1;register char C=getchar() ;
    while(C<'0'or C>'9')f=C=='-'?-1:1,C=getchar() ;
    while(C<='9'and C>='0')Q=(Q<<1)+(Q<<3)+C-'0',C=getchar() ;
    return f*Q;
}
void add(int i,int j,int v,bool flag)
{
    e[++tot].next=head[i];
    e[tot].to=j;
    head[i]=tot;
    e[tot].v=v;
    e[tot].f=flag;
}
void dfs(int x,int sum,int cnt)
{
    if(cnt>k)
    {
        return ;
    }
    if(vis[x]==true)
    {
        ans=min(ans,sum);
        return ;
    }
    if(sum>=dis[x][cnt])
    {
        return ;
    }
    vis[x]=true;
    dis[x][cnt]=sum;
    for(int i=head[x];i!=0;i=e[i].next)
    {
        int u=e[i].to;
        dfs(u,sum+e[i].v,cnt+(e[i].f?1:0));
    }
    vis[x]=false;
}
int main()
{
    freopen("trolley.in","r",stdin);
    freopen("trolley.out","w",stdout);
    n=read();m=read();k=read();
    for(int i=1;i<=n;i++)
    {
        int x=read(),y=read(),v=read();
        add(x,y,v,false);
    }
    for(int i=1;i<=abs(m-n);i++)
    {
        int x=read(),y=read(),v=read();
        add(x,y,v,true);
    }
    memset(dis,0x3f,sizeof(dis));
    for(int i=1;i<=k;i++)
    {
        dis[0][i]=0;
    }
    dfs(1,0,0);
    cout<<ans<<endl;
    return 0;
}

the end
撒花awa


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM