Codeforces 987 K预处理BFS 3n,7n+1随机结论题/不动点逆序对 X&Y=0连边DFS求连通块数目

A

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
const int mod = 1e9 + 7;
const int gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int N = 55 + 5;
int n, K;
ll sum[N][N];
ll a[N];
bool dp[N][N];
map<string, int> mp2;
map<int, string> mp;
int visit[10];
int main()
{
        ios_base::sync_with_stdio(0);
        cin.tie(0);
        mp2["purple"] = 1;
        mp2["green"] = 2;
        mp2["blue"] = 3;
        mp2["orange"] = 4;
        mp2["red"] = 5;
        mp2["yellow"] = 6;
        mp[1] = "Power";
        mp[2] = "Time";
        mp[3] = "Space";
        mp[4] = "Soul";
        mp[5] = "Reality";
        mp[6] = "Mind";
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
                string now;
                cin >> now;
                visit[mp2[now]]++;
        }
        cout << 6 - n << endl;
        for (int i = 1; i <= 6; i++)
        {
                if (!visit[i])
                {
                        cout << mp[i] << endl;
                }
        }
        return 0;
}
View Code

B

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
const int mod = 1e9 + 7;
const int gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int N = 55 + 5;
int main()
{
        ios_base::sync_with_stdio(0);
        cin.tie(0);
        ll x, y;
        cin >> x >> y;
        if (x == y || x == 2 && y == 4 || x == 4 && y == 2)
        {
                cout << "=" << endl;
                return 0;
        }
        if (x == 1 || y == 1)
        {
                if (x == 1)
                {
                        cout << "<" << endl;
                }
                else
                {
                        cout << ">" << endl;
                }
                return 0;
        }
        if (max(x, y) <= 10)
        {
                ll ansx = 1;
                for (int i = 1; i <= y; i++)
                {
                        ansx *= x;
                }
                ll ansy = 1;
                for (int i = 1; i <= x; i++)
                {
                        ansy *= y;
                }
                if (ansx > ansy)
                {
                        cout << ">" << endl;
                }
                else
                {
                        cout << "<" << endl;
                }
                return 0;
        }
        if (x > y)
        {
                cout << "<" << endl;
        }
        else
        {
                cout << ">" << endl;
        }
        return 0;
}
View Code

C

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
const int mod = 1e9 + 7;
const int gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int N = 55 + 5;
int num[3005];
ll cost[3005];
ll dp[3005][4];
int main()
{
        ios_base::sync_with_stdio(0);
        cin.tie(0);
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
                cin >> num[i];
        }
        for (int i = 1; i <= 3000; i++)
        {
                for (int j = 1; j <= 3; j++)
                {
                        dp[i][j] = LLONG_MAX;
                }
        }
        for (int i = 1; i <= n; i++)
        {
                cin >> cost[i];
                dp[i][1] = cost[i];
        }
        for (int i = 2; i <= n; i++)
        {
                for (int j = i - 1; j >= 1; j--)
                {
                        for (int k = 2; k <= 3; k++)
                        {
                                if (dp[j][k - 1] != LLONG_MAX&&num[i]>num[j])
                                {
                                        dp[i][k] = min(cost[i] + dp[j][k - 1], dp[i][k]);
                                }
                        }
                }
        }
        ll anser = LLONG_MAX;
        for (int i = 1; i <= n; i++)
        {
                anser = min(anser, dp[i][3]);
        }
        if (anser == LLONG_MAX)
        {
                cout << -1 << endl;
        }
        else
        {
                cout << anser << endl;
        }
        return 0;
}
View Code

D. Fair

题意:

给你N个点M条边的连通图(100000) 和K个特殊地方(100) S个目标地(100)

每个特殊的地方有某种特产 问你从1到N每个点要拿S个特产的最少的花费

解:

给每个特产都建一个超级点 然后BFS 处理出1到N每个点到每种特产的最小距离

然后贪心取前S个即可 复杂度nklogk

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
const int mod = 1e9 + 7;
const int gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int N = 1e5 + 105;
int p[N];
vector<int> g[N];
int ans[N];
int dist[N];
int que[N];
int dp[N][105];
int getl, getr;
int main()
{
        ios_base::sync_with_stdio(0);
        cin.tie(0);
        int n, m, k, s;
        cin >> n >> m >> k >> s;
        for (int i = 1; i <= n; i++)
        {
                cin >> p[i];
        }
        int u, v;
        for (int i = 1; i <= m; i++)
        {
                cin >> u >> v;
                g[u].pb(v);
                g[v].pb(u);
        }
        for (int i = 1; i <= k; i++)
        {
                getl = 1;
                getr = 0;
                mem(dist, 0);
                for (int j = 1; j <= n; j++)
                {
                        if (p[j] == i)
                        {
                                dist[j] = 1;
                                que[++getr] = j;
                        }
                }
                while (getl <= getr)
                {
                        int len = g[que[getl]].size();
                        for (int w = 0; w < len; w++)
                        {
                                int to = g[que[getl]][w];
                                if (!dist[to])
                                {
                                        dist[to] = dist[que[getl]] + 1;
                                        que[++getr] = to;
                                }
                        }
                        getl++;
                }
                for (int j = 1; j <= n; j++)
                {
                        dp[j][i] = dist[j] - 1;
                }
        }
        for (int i = 1; i <= n; i++)
        {
                sort(dp[i] + 1, dp[i] + 1 + k);
        }
        for (int i = 1; i <= n; i++)
        {
                for (int j = 1; j <= s; j++)
                {
                        ans[i] += dp[i][j];
                }
        }
        for (int i = 1; i <= n; i++)
        {
                cout << ans[i] << " ";
        }
        cout << endl;
        return 0;
}
View Code

E. Petr and Permutations

题意:

给你1到N的一种排列 A会选3n次每次随机一对位置交换 B会选7n+1次

问你给你的数列是A得到的可能性大还是B的可能性大

①:

可以猜到结论 观察可以得知3n和7n+1的奇偶性永远是不同的

所以我们计算原数列所需要的最小交换次数 当这个次数与A奇偶性相同就是A 反之则是B

(因为要与原数列相同的话在最小交换次数基础上要加偶数次)

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
const int mod = 1e9 + 7;
const int gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int N = 1e6 + 105;
int par[N], hs[N];
int sz[N];
int num[N];
int cnt;
void init(int n)
{
        for (int i = 0; i <= n; i++)
        {
                par[i] = i, hs[i] = i, sz[i] = 1;
        }
}
int find(int x)
{
        return par[x] == x ? x : par[x] = find(par[x]);
}
void unite(int x, int y)
{
        x = find(x);
        y = find(y);
        if (x != y)
        {
                par[x] = y, sz[y] += sz[x];
        }
}
int visit[N];
int main()
{
        ios_base::sync_with_stdio(0);
        cin.tie(0);
        int n;
        cin >> n;
        init(n);
        for (int i = 1; i <= n; i++)
        {
                cin >> num[i];
        }
        for (int i = 1; i <= n; i++)
        {
                if (num[i] != i)
                {
                        unite(i, num[i]);
                }
        }
        for (int i = 1; i <= n; i++)
        {
                par[i] = find(i);
        }
        ll anser = 0;
        for (int i = 1; i <= n; i++)
        {
                if (!visit[par[i]])
                {
                        anser += sz[par[i]] - 1;
                        visit[par[i]] = 1;
                }
        }
        //cout << anser << endl;
        if (anser % 2 == 3 * n % 2)
        {
                cout << "Petr" << endl;
        }
        else
        {
                cout << "Um_nik" << endl;
        }
        return 0;
}
View Code

②:

也可以用不动点+逆序对分情况处理

当n不小于20000时 考察不动点的数量  n小于20000时取逆序对的数量判断奇偶性

int main()
{
    int i,j,a1,a2;
    _(n);
    fo(i,n)
        _(a[i]);
    fo(i,n)
        an+=(a[i]==i);
    if(n>=20000)
        puts(an>=20?"Petr":"Um_nik");
    else
    {
        fo(i,n)            
        fo1(j,i+1,n)
            if(a[j]<a[i])
                ans++;
        puts((ans+n)%2?"Um_nik":"Petr");
    }
}
View Code

F. AND Graph

题意:

给你0 - 2n-1范围中的m个数 (n<=22)

如果两个数字Ai A两个&的值为0 则这两个点之间有一条边 问你最后的连通块有几个

解:

暴力题.. 假设有X,Y两个数 X的二进制恰好是Y的基础上多出一位1  比如 101 与 001 我们称X为Y的祖先 Y是X的子孙

这样能与祖先X相连的点 肯定能和Y相连 这样X,Y其实就通过对立数间接相连

所以我们每次DFS一个数的时候 把X全部子孙找出来 也把所有对立数(包括子孙的)找出来 他们肯定就是一个连通块

因为N最大是22 所以我们可以直接暴力循环枚举 开两个bool 数组 num[i]为true表示i是被选中的数 而vis[i]为true表示i被DFS过了

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
const int mod = 1e9 + 7;
const int gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int N = (1 << 22) + 5;
int n, m, now;
int anser;
bool num[N], vis[N];
void dfs(int x)
{
        if (vis[x])  //如果之前已经DFS到过
        {
                return ;
        }
        vis[x] = true;
        for (int i = 0; i < n; i++)
                if (x & (1 << i))  //DFS每个二进制比X少一位1的数保证main循环中不会被循环到
                {
                        dfs(x ^ (1 << i));
                }
        if (num[x])  //如果X是存在的 找所有X对立面的数
        {
                dfs((1 << n) - 1 - x);
        }
}
int main()
{
        cin >> n >> m;
        for (int i = 1; i <= m; i++)
        {
                scanf("%d", &now);
                num[now] = true;
        }
        for (int i = (1 << n) - 1; i >= 0; i--)
                if (!vis[i] && num[i])  //如果有存在的数且没有被DFS到
                {
                        anser++;  //连通块答案数+1
                        dfs((1 << n) - 1 - i); //DFS全部与i连通的数
                }
        cout << anser << endl;
        return 0;
}
View Code

 

posted @ 2018-05-30 13:43  Aragaki  阅读(366)  评论(0编辑  收藏  举报