Codeforces #301 Div 2 簡要題解

比賽總結

這次比賽和上次發揮得差不多,做了四個題,比較不爽的是其中兩個題因爲沒讀清楚題都wa了樣例,這裏損失了點罰時
提交記錄
這裏寫圖片描述

在正式和非正式選手中排名144名(可以看出我的罰時有多麼慘了吧233,每個題的得分基本上打了一半的折扣)
這裏寫圖片描述
在正式選手裏排名15名

A. Combination Lock

題目鏈接

http://codeforces.com/contest/540/problem/A

題目大意

給你一個大小爲n 的密碼鎖,每次轉動(0->1,1->2…9->0,1->0…)需要一單位時間,給你密碼鎖初始狀態和終止狀態,問最少要操作多長時間纔行。

思路

水題,不解釋

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

using namespace std;

char s[1100];
int st[1100],ed[1100];

int main()
{
    int n,ans=0;
    scanf("%d",&n);
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
        st[i]=s[i]-'0';
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
        ed[i]=s[i]-'0';
    for(int i=1;i<=n;i++)
    {
        int t=abs(st[i]-ed[i]);
        t=min(t,st[i]+10-ed[i]);
        t=min(t,ed[i]+10-st[i]);
        ans+=t;
    }
    printf("%d\n",ans);
    return 0;
}

B. School Marks

題目鏈接

http://codeforces.com/contest/540/problem/B

題目大意

給你一個長度爲n 的序列,序列裏要求每一項在區間[1,p],其中前k 項已經填好了,要你構造完剩餘的nk 項,使得所有項之和不超過x ,且中位數大於等於y,輸出一組可行解。

思路

我們對已經填好的前k 項進行排序,問題轉變爲在這個有序序列裏不斷地加入nk 項元素,讓有序序列的n+12 項大於等於y 。如果我們想要讓數字爲y 的最左邊的項往右邊走,就要加入<y 的數字,如果我們想要讓數字爲y 的最左邊的項往左邊走,就要加入>=y 的數字,但是題目又限制所有項之和不超過x ,因此我們要加入的項的數字都必須儘量小。因此我們加入的數字要麼是1 ,要麼是y 。我們儘量先填y ,如果發現還沒有填的部分全部填1的話就會使所有數字之和超出x ,我們就換成填1,這樣構造完的序列如果不能滿足條件的話,那麼顯然就是無解了。

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <map>

#define MAXN 1100

using namespace std;

int a[MAXN],tmp[MAXN];
int n,K,P,L,R,sum=0;

int main()
{
    scanf("%d%d%d%d%d",&n,&K,&P,&R,&L);
    for(int i=1;i<=K;i++) scanf("%d",&a[i]),tmp[i]=a[i],sum+=a[i];
    if(sum+n-K>R)
    {
        printf("-1\n");
        return 0;
    }
    for(int i=K+1;i<=n;i++)
    {
        if(sum+L+n-i<=R)
        {
            a[i]=L;
            sum+=L;
        }
        else
        {
            a[i]=1;
            sum++;
        }
        tmp[i]=a[i];
    }
    sort(tmp+1,tmp+n+1);
    if(tmp[(1+n)/2]>=L)
    {
        for(int i=K+1;i<=n;i++) printf("%d ",a[i]);
        printf("\n");
    }
    else printf("-1\n");
    return 0;
}

C. Ice Cave

題目鏈接

http://codeforces.com/contest/540/problem/C

題目大意

給你一個nm 列的地圖,每個格子上要麼是’.’,要麼是’X’,你只能經過格子’.’。你每經過一個格子,就會把它從’.’變成’X’,問你是否能這樣從(xs,ys) 走到(xt,yt) ,並且走到(xt,yt) 後,再繞一圈走回已經變成’X’的(xt,yt)

思路

直接BFS就好了,如果碰見已經變成了’X’的(xt,yt) 就表明存在這樣的路線,否則如果當前的格子是’X’就不繼續拓展,否則繼續往四個方向分別拓展移動

爲什麼這樣做就是對的呢?因爲如果最先存在一條走到還是’.’的格子(xt,yt) ,就可以繼續走,並轉一圈回到’X’。之後走到已經變爲’X’的(xt,yt) 的路線的話,肯定是圍繞着最開始的那個路徑的終點繞了一圈,正好就給(xt,yt) 留了幾個空格(最少三個),就能繞一圈走回來了

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <map>

#define MAXN 610

using namespace std;

int n,m;
char mp[MAXN][MAXN];
int sx,sy,tx,ty;
pair<int,int> q[MAXN*MAXN*4];
int xx[]={1,-1,0,0},yy[]={0,0,1,-1};

bool inMap(int i,int j)
{
    if(i<1||i>n||j<1||j>m) return false;
    return true;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
    scanf("%d%d",&sx,&sy);
    scanf("%d%d",&tx,&ty);
    int h=0,t=1;
    q[h]=make_pair(sx,sy);
    while(h<t)
    {
        pair<int,int>now=q[h++];
        int nowx=now.first,nowy=now.second;
        for(int dir=0;dir<4;dir++)
        {
            int nextx=nowx+xx[dir],nexty=nowy+yy[dir];
            if(!inMap(nextx,nexty)) continue;
            if(mp[nextx][nexty]=='X')
            {
                if(nextx==tx&&nexty==ty)
                {
                    printf("YES\n");
                    return 0;
                }
                continue;
            }
            mp[nextx][nexty]='X';
            q[t++]=make_pair(nextx,nexty);
        }
    }
    printf("NO\n");
    return 0;
}

D. Bad Luck Island

題目鏈接

http://codeforces.com/contest/540/problem/D

題目大意

現在有r 個石頭,s 個剪刀,p 個布,每回合會從中隨機挑選兩種種類的物品玩石頭剪刀布,輸的那方會減少一個物品,問最終只有石頭存活、只有剪刀存活、只有布存活的期望各是多少。

思路

顯然是個概率DP題。用f[i][j][k] 表示還有i 個石頭,j 個剪刀,k 個布的情況的期望。f[i][j][k] 是從f[i+1][j][k]f[i][j+1][k]f[i][j][k+1] 推來的,現在考慮f[i][j+1][k] 如何轉移到f[i][j][k] 。顯然是上一局石頭和剪刀碰面了,根據乘法計數,這種情況共有i(j+1) 種,兩種不同種類的物品碰面總共有i(j+1)+(j+1)k+ik 種情況,因此出現石頭和剪刀碰面的概率是i(j+1)i(j+1)+(j+1)k+ikf[i][j][k]+=i(j+1)i(j+1)+(j+1)k+ikf[i][j+1][k] ,其他兩種情況也差不多

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <map>

#define MAXN 610

using namespace std;

double f[110][110][110];
int r,s,p;

double DFS(int i,int j,int k)
{
    if(f[i][j][k]) return f[i][j][k];
    //if(!i&&!j&&!k) continue;
    //if(i==r&&j==s&&k==p) continue;
    if(j+1<=s&&i) f[i][j][k]+=DFS(i,j+1,k)*(double)(i*(j+1))/(double)(i*(j+1)+(j+1)*k+k*i);
    if(k+1<=p&&j) f[i][j][k]+=DFS(i,j,k+1)*(double)(j*(k+1))/(double)(i*j+j*(k+1)+(k+1)*i);
    if(i+1<=r&&k) f[i][j][k]+=DFS(i+1,j,k)*(double)((i+1)*k)/(double)((i+1)*j+j*k+k*(i+1));
    return f[i][j][k];
}

int main()
{
    scanf("%d%d%d",&r,&s,&p);
    f[r][s][p]=1;
    double ans1=0,ans2=0,ans3=0;
    for(int i=1;i<=r;i++) ans1+=DFS(i,0,0);
    for(int i=1;i<=s;i++) ans2+=DFS(0,i,0);
    for(int i=1;i<=p;i++) ans3+=DFS(0,0,i);
    printf("%.11lf %.11lf %.11lf\n",ans1,ans2,ans3);
    return 0;
}

E. Infinite Inversions

題目鏈接

http://codeforces.com/contest/540/problem/E

題目大意

給你一個無限長的序列1,2,3... ,以及q 個操作,每次操作會交換這個序列裏下標爲xy 的元素。問最終這個序列裏有多少對逆序對

思路

假如每次操作的下標的範圍是在[1,n] 範圍內,則顯然這個序列只保留[1,n] 部分的話答案是不變的。

所以我們可以用map來模擬交換元素的操作,然後對被修改過的那些序列元素做離散化,得到這些被修改的數字的排名、以及排名爲i 的數字是什麼,然後我們可以離散化出一個新的序列,這個序列長度最多爲2q,我們先求出這個序列的逆序對個數,這些逆序對(ai,bi)aibi 都是被操作過的數字。然後我們還需要求出其他的逆序對(ai,bi)aibi 裏有一個是被操作過的數字。

看下面這個序列:
6 2 3 4 9 1 7 8 5
對於第一個數字6而言,它現在在位置1,原來在位置6,[1,6] 區間裏,有3個被操作過的數字,還有3個是沒有被操作過的數字,因此給最終答案貢獻3

以此類推,我們枚舉被修改的每個數字,找到它當前所在的下標和初始的下標之間的區間裏有多少個沒被操作過的數字,添加進答案

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <map>

#define MAXN 410000
#define lowbit(x) ((x)&(-(x)))

using namespace std;

typedef long long int LL;

map<int,int>mp,mp2; //mp2[i]=數字i的排名
map<int,int>::iterator it,it2;
LL bit[MAXN];
int n;

void update(int x,LL val)
{
    while(x<=n)
    {
        bit[x]+=val;
        x+=lowbit(x);
    }
}

LL query(int x)
{
    LL ans=0;
    while(x)
    {
        ans+=bit[x];
        x-=lowbit(x);
    }
    return ans;
}

int a[MAXN]; //a[]裏保存的是離散化後的序列
pair<int,int> opt[MAXN];
int sta[MAXN*2],top=0; //sta[i]=排名爲i的數字

bool cmp(int x,int y)
{
    return sta[x]<sta[y];
}

LL ans=0;

int main()
{
    int q;
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        it=mp.find(x);
        it2=mp.find(y);
        if(it==mp.end()) mp[x]=x;
        if(it2==mp.end()) mp[y]=y;
        opt[i]=make_pair(x,y);
        it=mp.find(x);
        it2=mp.find(y);
        swap(it->second,it2->second);
    }
    for(it=mp.begin();it!=mp.end();it++)
        mp2[it->second]=++top,sta[top]=it->second;
    /*for(it=mp2.begin();it!=mp2.end();it++)
        cout<<"num: "<<it->first<<"rank: "<<it->second<<endl;*/
    for(int i=1;i<=top;i++) a[i]=i;
    for(int i=1;i<=q;i++)
        swap(a[mp2[opt[i].first]],a[mp2[opt[i].second]]);
    n=top;
    for(int i=n;i>=1;i--)
    {
        ans+=query(a[i]-1);
        update(a[i],1);
    }
    for(it=mp.begin();it!=mp.end();it++)
        ans+=abs(it->second-it->first)-abs(mp2[it->second]-mp2[it->first]);
    printf("%I64d\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章