Codeforces Round #390 (Div. 2)(A,B,C(記憶化搜尋),D(貪心,優先佇列))

CN_swords發表於2017-02-16
/*
Codeforces Round #390 (Div. 2)
時間: 2017/02/16
A. Lesha and array splitting
題意:將集合分成幾個小集合,要求小集合的和不為0.
題解:遍歷過去,一直到不滿足集合並數字非0前生成一個集合
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 110;

int a[N];
int rel[N],rer[N];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        int flag = 0;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&a[i]);
            if(a[i])
                flag = 1;
        }
        if(!flag)
            puts("NO");
        else
        {
            puts("YES");
            int r = 1,l = 1;
            int sum = 0;
            int k = 0;
            while(r <= n)
            {
                sum += a[r];
                if(!sum && a[r])
                {
                    rel[k] = l;
                    rer[k++] = r-1;
                    l = r;
                }
                else
                    r++;
            }
            rel[k] = l;
            rer[k++] = r-1;
            printf("%d\n",k);
            for(int i = 0; i < k; i++)
                printf("%d %d\n",rel[i],rer[i]);
        }
    }
    return 0;
}



/*
Codeforces Round #390 (Div. 2)
時間: 2017/02/16
B. Ilya and tic-tac-toe game
題意:給你一個4*4的棋盤,誰先連成三子誰贏,‘x’為先手下的棋,‘o’為後手下的棋,‘.’為空,問先手下一步能不贏
題解:將列舉每個空格位置,判斷位置可行性
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 10;

int p[N][N];
bool hefa(int x,int y)
{
    if(x >= 0 && x <= 3 && y >= 0 && y <= 3)
        return true;
    return false;
}
bool pan(int x,int y)
{
    if(hefa(x-1,y) && hefa(x-2,y) && p[x-1][y] == 1 && p[x-2][y] == 1)
        return true;
    if(hefa(x-1,y-1) && hefa(x-2,y-2) && p[x-1][y-1] == 1 && p[x-2][y-2] == 1)
        return true;
    if(hefa(x+1,y) && hefa(x+2,y) && p[x+1][y] == 1 && p[x+2][y] == 1)
        return true;
    if(hefa(x+1,y+1) && hefa(x+2,y+2) && p[x+1][y+1] == 1 && p[x+2][y+2] == 1)
        return true;
    if(hefa(x-1,y-1) && hefa(x+1,y+1) && p[x-1][y-1] == 1 && p[x+1][y+1] == 1)
        return true;
    if(hefa(x-1,y) && hefa(x+1,y) && p[x-1][y] == 1 && p[x+1][y] == 1)
        return true;

    if(hefa(x,y-1) && hefa(x,y-2) && p[x][y-1] == 1 && p[x][y-2] == 1)
        return true;
    if(hefa(x-1,y+1) && hefa(x-2,y+2) && p[x-1][y+1] == 1 && p[x-2][y+2] == 1)
        return true;
    if(hefa(x,y+1) && hefa(x,y+2) && p[x][y+1] == 1 && p[x][y+2] == 1)
        return true;
    if(hefa(x+1,y-1) && hefa(x+2,y-2) && p[x+1][y-1] == 1 && p[x+2][y-2] == 1)
        return true;
    if(hefa(x+1,y-1) && hefa(x-1,y+1) && p[x+1][y-1] == 1 && p[x-1][y+1] == 1)
        return true;
    if(hefa(x,y-1) && hefa(x,y+1) && p[x][y-1] == 1 && p[x][y+1] == 1)
        return true;
    return false;
}
int main()
{
    char s[N];
    while(~scanf("%s",s))
    {
        int a;
        for(int j = 0; j < 4; j++)
        {
            if(s[j] == 'x')
                a = 1;
            else if(s[j] == '.')
                a = 0;
            else
                a = 2;
            p[0][j] = a;
        }
        for(int i = 1; i < 4; i++)
        {
            scanf("%s",s);
            for(int j = 0; j < 4; j++)
            {
                if(s[j] == 'x')
                    a = 1;
                else if(s[j] == '.')
                    a = 0;
                else
                    a = 2;
                p[i][j] = a;
            }
        }
        int flag = 0;
        for(int i = 0; i < 4; i++)
        {
            for(int j = 0; j < 4; j++)
            {
                //printf("%d ",p[i][j]);
                if(!p[i][j] && pan(i,j))
                {
                    flag = 1;
                    break;
                }
            }
            //puts("");
            if(flag)
                break;
        }
        if(flag)
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}


/*
Codeforces Round #390 (Div. 2)
時間: 2017/02/17
C題 Vladik and chat
題意:給你幾段對話,和幾個說話人的名字,要求得到不可知說話人的名字。
秉承的原則:
1.一個人不可能說兩個連續的話
2.說話的人不能提到自己的名字
題解:
dp[i][j] = 1 代表第i句可能是j人說。
dp2[i][j] = 1 代表考慮前i-1句,第i-1句是j人說。
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;
const int N = 150;

map<string,int> mp;
int dp[N][N];
int dp2[N][N];
int res[N];
int flag;
int n,m;
int cal(int id, int limit)
{
    int &ret = dp2[id][limit];
    if (id > m)
        return ret = 1;
    if (ret != -1)
        return ret;
    ret = 0;
    for (int i = 1; i <= n; i++)
    {
        if(dp[id][i] && limit != i)
        {
            ret = max(ret, cal(id + 1, i));
        }
    }
    return ret;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        mp.clear();
        memset(dp,0,sizeof(dp));
        memset(dp2,-1,sizeof(dp2));
        scanf("%d",&n);
        getchar();
        string name[N];
        for(int i = 0; i < n; i++)
        {
            cin >> name[i+1];
            mp[name[i+1]] = i+1;
        }
        scanf("%d",&m);
        getchar();
        char s[N];
        string rec[N];
        flag = 1;
        for(int i = 1; i <= m; i++)
        {
            gets(s);
            int len = strlen(s);
            int j;
            string a;
            for(j = 0; j < len; j++)
            {
                if(s[j] == ':') break;
                a += s[j];
            }
            int begin = j;
            for(int j = begin; j < len; j++)
                rec[i] += s[j];
            if(a == "?")
            {
                for(int k = 1; k <= n; k++)
                    dp[i][k] = 1;
                for(j = begin; j < len; j++)
                {
                    if(!isalnum(s[j]))  continue;
                    string b;
                    int k;
                    for(k = j; k < len; k++)
                    {
                        if(!isalnum(s[k]))  break;
                        b += s[k];
                    }
                    j = k;
                    if(mp[b])
                        dp[i][mp[b]] = 0;
                }
            }
            else
            {
                int id = mp[a];
                dp[i][id] = 1;
                for(j = begin; j < len; j++)
                {
                    if(!isalnum(s[j]))  continue;
                    string b;
                    int k;
                    for(k = j; k < len; k++)
                    {
                        if(!isalnum(s[k]))  break;
                        b += s[k];
                    }
                    j = k;
                    if(b == a)
                    {
                        flag = 0;
                        break;
                    }
                }
            }
        }
        if(!flag)
            puts("Impossible");
        else
        {
            int ans = cal(1,0);
            if(!ans)
                puts("Impossible");
            else
            {
                int k;
                for (int i = 1; i <= n; i++)
                {
                    if (dp2[m + 1][i] == 1)
                    {
                        k = i;
                        break;
                    }
                }
                int id = m;
                while (1)
                {
                    res[id] = k;
                    if (id == 1)
                        break;
                    for (int i = 1; i <= n; i++)
                    {
                        if (k != i&&dp2[id][i] == 1)
                        {
                            k = i;
                            break;
                        }
                    }
                    id--;
                }
                for (int i = 1; i <= m; i++)
                    cout << name[res[i]] << rec[i] << endl;
            }
        }
    }
    return 0;
}





/*
Codeforces Round #390 (Div. 2)
時間: 2017/02/16
D. Fedor and coupons
題意:給你n個具有範圍的禮券,選擇k個禮券,要求k個禮券交叉包含的範圍最大,輸出範圍大小和選擇的禮券。
題解:要選k個禮券維護最大,我們要使禮券交叉左極限小,右極限大。這樣看來將禮券按左極限排序,然後右極限用優先佇列維護即可。

*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 300010;

struct asd
{
    int l,r,id;
    friend bool operator< (asd n1,asd n2)
    {
        return n1.r > n2.r;
    }
}a[N];
bool cmp(asd n1,asd n2)
{
    return n1.l < n2.l;
}
int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d",&a[i].l,&a[i].r);
            a[i].id = i;
        }
        sort(a+1,a+n+1,cmp);
        priority_queue<asd> q;
        int ans = 0,res = 0;
        for(int i = 1; i <= n; i++)
        {
            asd temp;
            if(!q.empty())
                temp = q.top();
            if(q.size() < k)
                q.push(a[i]);
            else if(temp.r < a[i].r)
            {
                q.pop();
                q.push(a[i]);
            }
            if(q.size() == k)
            {
                temp = q.top();
                if(temp.r-a[i].l+1 > ans)
                {
                    ans = temp.r-a[i].l+1;
                    res = i;
                }
            }
        }
        printf("%d\n",ans);
        if(ans)
        {
            int id = 0;
            for(int i = 1; i <= res && id < k; i++)
            {
                if(a[res].l+ans-1 <= a[i].r)
                {
                    printf("%d ",a[i].id);
                    id++;
                }
            }
        }
        else
        {
            for(int i = 1; i <= k; i++)
                printf("%d ",i);
        }
        puts("");
    }
    return 0;
}


相關文章