ICPC WF46 Y,W,P题题解

前言

WF试题册还是相当美观工整的,很赏心悦目。

昨天到今天上午,总共写出来三道题。第一题是自己写出来的,后两题是看cf上题解自己摸索的。

题解

Y题

题意看上去有点像模拟一个消数的过程。我仔细一想,结果无外乎几种可能

0  1  01  10  010  101

所以,首先消除连续的1和0串,变成1,0,101010,0101010等等这种。

例如11000110001,消除连续串之后变成10101.

然后,根据这个串,长度为1直接输出;否则能消除则直接消除后面的若干的01或10串,使长度变成最终的2或3.

例如,上述例子变成101.

标程

#include <iostream>
using namespace std;
#include <set>
#include <algorithm>
#include <cmath>
#include <map>
#include <cstdio>
#include <string>
#include <cstring>
#include <string.h>
#include <stdlib.h>
#include <iomanip>
#include <fstream>
#include <stdio.h>
#include <stack>
#include <queue>
#include <ctype.h>
#include <vector>
#include <random>
#include <bitset>
#define ll long long
#define ull unsigned long long
#define pb push_back
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define pii pair<int, int>
#define pli pair<ll, int>
#define pil pair<int, ll>
#define pll pair<ll, ll>
#define endl '\n'
const double pai = acos(-1);
ll extend_gcd(ll a, ll b, ll &x, ll &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll d = extend_gcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
ll fastpow(ll a, ll n, ll mod)
{
    ll ans = 1;
    a %= mod;
    while (n)
    {
        if (n & 1)
            ans = (ans * a) % mod; //% mod
        a = (a * a) % mod;         //% mod
        n >>= 1;
    }
    return ans;
}
int dir[4][2] =
    {
        {0, 1}, {0, -1}, {1, 0}, {-1, 0}}; // d a w s

const ll inf = 1000000000000000000ll;
const ll mod = 1e9 + 7, P1 = 13331;
const double eps = 1e-7;
const int N = 1e5 + 10, M = 1e4 + 10;

string s;


int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    //freopen("ain.txt", "r", stdin);freopen("aout.txt", "w", stdout);
    cin>>s;
    int len=s.size();
    string ans="";
    ans=ans+s[0];

    rep(i,1,len-1)
    {
        int len=ans.size();
        if(s[i]!=ans[len-1])
        {
            ans=ans+s[i];
        }    
    }
    if(ans.size()==1)
    {
        cout<<ans;
    }
    else
    {
        if(ans.size()%2==1)
        {
            cout<<ans[0]<<ans[1]<<ans[2];
        }
        else
        {
            cout<<ans[0]<<ans[1];
        }
    }


    return 0;
}
 

W题

这个题我是想了好多方法都没想出来,始终感觉差一步,后来看了题解,

1 0 0

0 1 0

0 0 1

1 1 1 

1 2 3

这样构造问法,甚是巧妙。这五个问无论哪一问撒谎,剩余四问都能自证是对的。

设第i问的回答的数字为a[i]

假设第五问撒谎,则前四问都没撒谎,a[1]+a[2]+a[3]==a[4]

假设第四问撒谎,a[1]+2*a[2]+3*a[3]==a[5]

假设第一问撒谎,则ans[1]=a[5]-2*a[2]-3*a[3],带入第四个式子,如果ans[1]+a[2]+a[3]==a[4],则可解得答案为ans[1],a[2],a[3]

标程

#include <iostream>
using namespace std;
#include <set>
#include <algorithm>
#include <cmath>
#include <map>
#include <cstdio>
#include <string>
#include <cstring>
#include <string.h>
#include <stdlib.h>
#include <iomanip>
#include <fstream>
#include <stdio.h>
#include <stack>
#include <queue>
#include <ctype.h>
#include <vector>
#include <random>
#include <bitset>
#define ll long long
#define ull unsigned long long
#define pb push_back
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define pii pair<int, int>
#define pli pair<ll, int>
#define pil pair<int, ll>
#define pll pair<ll, ll>
//#define endl '\n'
const double pai = acos(-1);
ll extend_gcd(ll a, ll b, ll &x, ll &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll d = extend_gcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
ll fastpow(ll a, ll n, ll mod)
{
    ll ans = 1;
    a %= mod;
    while (n)
    {
        if (n & 1)
            ans = (ans * a) % mod; //% mod
        a = (a * a) % mod;         //% mod
        n >>= 1;
    }
    return ans;
}
int dir[4][2] =
    {
        {0, 1}, {0, -1}, {1, 0}, {-1, 0}}; // d a w s

const ll inf = 1000000000000000000ll;
const ll mod = 1e9 + 7, P1 = 13331;
const double eps = 1e-7;
const int N = 1e5 + 10, M = 1e4 + 10;

int a[10];


int main()
{
    //ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    //freopen("ain.txt", "r", stdin);freopen("aout.txt", "w", stdout);
    cout<<"1 0 0"<<endl;
    cin>>a[1];
    cout<<"0 1 0"<<endl;
    cin>>a[2];
    cout<<"0 0 1"<<endl;
    cin>>a[3];
    cout<<"1 1 1"<<endl;
    cin>>a[4];
    cout<<"1 2 3"<<endl;
    cin>>a[5];
    if(a[1]+a[2]+a[3]==a[4])
    {
        cout<<a[1]<<" "<<a[2]<<" "<<a[3]<<endl;
        exit(0);
    }
    int tem=a[4]-a[2]-a[3];
    if(tem+2*a[2]+3*a[3]==a[5])
    {
        cout<<tem<<" "<<a[2]<<" "<<a[3]<<endl;
        exit(0);
    }

    tem=a[4]-a[1]-a[3];
    
    if(a[1]+2*tem+3*a[3]==a[5])
    {
        cout<<a[1]<<" "<<tem<<" "<<a[3]<<endl;
        exit(0);
    }
    tem=a[4]-a[1]-a[2];
    if(a[1]+2*a[2]+3*tem==a[5])
    {
        cout<<a[1]<<" "<<a[2]<<" "<<tem<<endl;
        exit(0);
    }
    cout<<a[1]<<" "<<a[2]<<" "<<a[3]<<endl;

    return 0;
}
 

P题

今天早上做的一道题,一开始觉得可能是解方程组,高斯消元,但一看数据范围不对。后来已经看出来考察图论,联通分量,有点像拓扑排序,但又感觉无从下手。不知道怎么写这个复杂的程序。

建模:简单来说,对于第i个灯,c[i]记录这个灯颜色对应的数字,red c[i]=0,green c[i]=1,blue c[i]=2。

对于每一个按钮,无外乎三种可能,开0或1或2次。因为这个题是对3取模。

那么怎么写程序呢。

我的方法是遍历所有的灯,若这个灯没有按钮控制,看它颜色,不是红色直接impossible。

  若只有一个按钮控制,那么这个按钮按几次是确定的,设这是第i个按钮,ding[i]记录它按几次。

然后考虑这个按钮影响到的其他的灯,假设影响到了j灯,倘若j灯只被第i个按钮所控制,那么看看(c[j]+ding[i])%3是否为0 ,为0 则正确,否则impossible。

倘若j灯被两个按钮控制,那么i按钮按几次定了,另一个按钮按几次也能定下来,根据初始颜色和i按钮按几次。再把这个按钮影响到的灯都这样考察一遍。

这是个复杂的过程。

结束后,这些灯vis标记为1,后续遍历时不再考虑。

倘若遍历时一个灯被两个按钮控制,那么比较复杂,枚举,这两个灯颜色有三种可能,都枚举一遍,过程同上。若三种可能都最终导致impossible,那么输出impossible。这三种情况可行的情况计算按按钮的次数的最小值,加在ans上。

标程

#include <iostream>
using namespace std;
#include <set>
#include <algorithm>
#include <cmath>
#include <map>
#include <cstdio>
#include <string>
#include <cstring>
#include <string.h>
#include <stdlib.h>
#include <iomanip>
#include <fstream>
#include <stdio.h>
#include <stack>
#include <queue>
#include <ctype.h>
#include <vector>
#include <random>
#include <bitset>
#define ll long long
#define ull unsigned long long
#define pb push_back
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define pii pair<int, int>
#define pli pair<ll, int>
#define pil pair<int, ll>
#define pll pair<ll, ll>
// #define endl '\n'
const double pai = acos(-1);
ll extend_gcd(ll a, ll b, ll &x, ll &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll d = extend_gcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
ll fastpow(ll a, ll n, ll mod)
{
    ll ans = 1;
    a %= mod;
    while (n)
    {
        if (n & 1)
            ans = (ans * a) % mod; //% mod
        a = (a * a) % mod;         //% mod
        n >>= 1;
    }
    return ans;
}
int dir[4][2] =
    {
        {0, 1}, {0, -1}, {1, 0}, {-1, 0}}; // d a w s

const ll inf = 1000000000000000000ll;
const ll mod = 1e9 + 7, P1 = 13331;
const double eps = 1e-7;
const int N = 4e5 + 10, M = 1e4 + 10;

int l, b;
string s;
int c[N];
int x[N][3];
int ans;
bool vis[N];
vector<int> ying[N];

struct node
{
    int id, add;
    node(int a, int b)
    {
        id = a;
        add = b;
    }
};

int ding[N]; // jilu mouyige deng shifou dingle

void cuo()
{
    cout << "impossible";
    exit(0);
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
   // freopen("ain.txt", "r", stdin);
   // freopen("aout.txt", "w", stdout);
    cin >> l >> b;
    cin >> s;
    s = ' ' + s;
    rep(i, 1, l)
    {

        if (s[i] == 'R')
        {
            c[i] = 0;
        }
        else if (s[i] == 'G')
        {
            c[i] = 1;
        }
        else
        {
            c[i] = 2;
        }
    }
    rep(i, 1, b)
    {
        ding[i] = -1;
        int k;
        cin >> k;
        rep(j, 1, k)
        {
            int temp;
            cin >> temp;
            ying[i].pb(temp);
            if (x[temp][1])
            {

                x[temp][2] = i;
            }
            else
            {

                x[temp][1] = i;
            }
        }
    }
    rep(i, 1, l)
    {
        if (vis[i]) // zhege dian meikaolv guo
        {
            continue;
        }
        if (x[i][1] == 0)
        {
            if (c[i])
            {
                cuo();
            }
        }
        else if (x[i][2] == 0)
        {
            rep(jj, 0, 2)
            {
                if ((c[i] + jj) % 3 == 0)
                {
                    ding[x[i][1]] = jj;
                    ans += jj;
                    break;
                }
            }
            queue<int> q;
            for (auto j : ying[x[i][1]])
            {
                q.push(j);
            }
            //
           // cout<<x[1][1]<<" "<<ding[x[1][1]]<<endl;
            while (q.size())
            {
                int u = q.front();
                vis[u] = 1;
                //
                // cout<<i<<" "<<u<<endl;
                q.pop();
                if (x[u][2] == 0)
                {

                    if ((c[u] + ding[x[u][1]]) % 3 == 0)
                    {
                        continue;
                    }
                    else
                    {
                        cuo();
                    }
                }

                if (x[u][2])
                {
                    if (ding[x[u][1]] > -1 && ding[x[u][2]] > -1)
                    {
                        if ((c[u] + ding[x[u][1]] + ding[x[u][2]]) % 3 == 0)
                        {
                            continue;
                        }
                        cuo();
                    }
                    if (ding[x[u][1]]>-1)
                    {
                        rep(j, 0, 2)
                        {
                            if ((c[u] + ding[x[u][1]] + j) % 3 == 0)
                            {
                                ding[x[u][2]] = j;
                                ans += j;
                                for (auto jj : ying[x[u][2]])
                                {
                                    q.push(jj);
                                }
                            }
                        }
                    }
                    else
                    {
                        rep(j, 0, 2)
                        {
                            if ((c[u] + ding[x[u][2]] + j) % 3 == 0)
                            {
                                ding[x[u][1]] = j;
                                ans += j;
                                for (auto jj : ying[x[u][1]])
                                {
                                    q.push(jj);
                                }
                            }
                        }
                    }
                }
            }
        }
        else if (x[i][2])
        {
            ll temp=inf;
            rep(jj, 0, 2)
            {
                ll tem=0;
                queue<int > qing;
                
                ding[x[i][1]] = jj;
                qing.push(x[i][1]);
                qing.push(x[i][2]);
                tem += jj;
                rep(jjj,0,2)
                {
                    if((c[i]+jj+jjj)%3==0)
                    {
                        ding[x[i][2]]=jjj;
                        tem+=jjj;
                    }
                }

                queue<int> q;
                for (auto j : ying[x[i][1]])
                {
                    q.push(j);
                }
                for(auto j:ying[x[i][2]])
                {
                    q.push(j);
                }

                while (q.size())
                {
                    int u = q.front();
                    vis[u] = 1;
                    //
                    // cout<<i<<" "<<u<<endl;
                    q.pop();
                    if (x[u][2] == 0)
                    {
                        if ((c[u] + ding[x[u][1]]) % 3 == 0)
                        {
                            continue;
                        }
                        else
                        {
                            goto tt;
                        }
                    }

                    if (x[u][2])
                    {
                        if (ding[x[u][1]] > -1 && ding[x[u][2]] > -1)
                        {
                            if ((c[u] + ding[x[u][1]] + ding[x[u][2]]) % 3 == 0)
                            {
                                continue;
                            }
                            goto tt;
                        }
                        if (ding[x[u][1]]>-1)
                        {
                            rep(j, 0, 2)
                            {
                                if ((c[u] + ding[x[u][1]] + j) % 3 == 0)
                                {
                                    ding[x[u][2]] = j;
                                    qing.push(x[u][2]);
                                    tem += j;
                                    for (auto jj : ying[x[u][2]])
                                    {
                                        q.push(jj);
                                    }
                                }
                            }
                        }
                        else
                        {
                            rep(j, 0, 2)
                            {
                                if ((c[u] + ding[x[u][2]] + j) % 3 == 0)
                                {
                                    ding[x[u][1]] = j;
                                    qing.push(x[u][1]);
                                    tem += j;
                                    for (auto jj : ying[x[u][1]])
                                    {
                                        q.push(jj);
                                    }
                                }
                            }
                        }
                    }
                }
                temp=min(temp,tem);
tt:

                while(qing.size())
                {
                    int u=qing.front();
                    ding[u]=-1;
                    qing.pop();
                }
                
            }
            if(temp==inf)
            {
                cuo();
            }
            ans+=temp;
        }
    }
    cout << ans;

    return 0;
}
 

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值