hdu 多校赛 第五场

slove  2/10

rank  434

补题   5/10

---------------------------------------------------

link

6624 fraction

https://blog.csdn.net/qq_41608020/article/details/98942305

6625 three arrays

两个长度为n的数组a,b,规定数组 c_i = a_i \& b_i,  a b数组之间可以任意改变位置。求最小字典序的c数组

首先给a b数组分别建立字典树,二进制取&运算,数位的值相同时合成的数字最小,所以dfs在树上跑就行。

这个地方有个坑点,在dfs时,只有在到达数字的末尾才加入数字,并且可以知道数字出现的次数,但是如果在最后判断末尾时判断数字出现次数是否大于0会超时,所以在dfs时就判断数字出现次数是否大于0。

#include
using namespace std;
#define ll long long
typedef vector  Vi;
typedef vector VI;
typedef pair pii;
#define pb push_back
#define mk make_pair
#define sc scanf
#define pr printf
const int N = 1e5 + 10;
struct Trie
{
	int nex[N * 30][2], cnt[N * 30];
	bool end[N * 30];
	int root, idx;
	int newnode()
	{
		++idx;
		memset(nex[idx], 0, sizeof(nex[idx]));
		end[idx] = 0, cnt[idx] = 0;
		return idx;
	}
	void init()
	{
		idx = 0;
		root = newnode();
	}
	void insert(int x)
	{
		int p = root;
		for (int i = 29; i >= 0; i--)
		{
			int c = 1 & (x >> i);
			if (!nex[p][c])
			{
				nex[p][c] = newnode();
			}
			p = nex[p][c];
			++cnt[p];
		}
		end[p] = 1;
	}
}t1, t2;

int c1[N], c2[N];
vector ans;
void dfs(int rt1, int rt2, int x)
{
	int e = min(t1.cnt[rt1], t2.cnt[rt2]);
	t1.cnt[rt1] -= e, t2.cnt[rt2] -= e;
	if (t1.end[rt1])
	{
		ans.pb(mk(x, e));
		return;
	}
	if (t1.cnt[t1.nex[rt1][0]] && t2.cnt[t2.nex[rt2][0]])
		dfs(t1.nex[rt1][0], t2.nex[rt2][0], x << 1);
	if (t1.cnt[t1.nex[rt1][1]] && t2.cnt[t2.nex[rt2][1]])
		dfs(t1.nex[rt1][1], t2.nex[rt2][1], x << 1);
	if (t1.cnt[t1.nex[rt1][1]] && t2.cnt[t2.nex[rt2][0]])
		dfs(t1.nex[rt1][1], t2.nex[rt2][0], x << 1 | 1);
	if (t1.cnt[t1.nex[rt1][0]] && t2.cnt[t2.nex[rt2][1]])
		dfs(t1.nex[rt1][0], t2.nex[rt2][1], x << 1 | 1);
}
int main()
{
	int T;
	sc("%d", &T);
	while (T--)
	{
		ans.clear();
		int n;
		sc("%d", &n);
		t1.init();
		for (int i = 1; i <= n; i++)
		{
			sc("%d", &c1[i]);
			t1.insert(c1[i]);
		}
		t2.init();
		for (int i = 1; i <= n; i++)
		{
			sc("%d", &c2[i]);
			t2.insert(c2[i]);
		}
		dfs(t1.root, t2.root, 0);
		sort(ans.begin(), ans.end());
		for (int i = 0; i < ans.size(); i++)
		{
			for (int j = 1; j <= ans[i].second; j++)
				printf(j == ans[i].second ? "%d" : "%d ", ans[i].first);
			if (i != ans.size() - 1)
				printf(" ");
		}
		printf("\n");
	}
	
}
/*
ababcababababcabab
*/
#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAX_NODE = 1e5 + 5;
const int qwe = 29;
struct Trie
{
    int nex[2];
    int val;
}a[MAX_NODE * 31], b[MAX_NODE * 31];
int cnt1, cnt2;
int ans[100005];
char s[32];
int n, t;
void init()
{
    memset(a[0].nex, 0, sizeof(a[0].nex));
    a[0].val = 0;
    cnt1 = 1;

    memset(b[0].nex, 0, sizeof(b[0].nex));
    b[0].val = 0;
    cnt2 = 1;
}
void insert(char* s, int infor, int op)
{
    int len = qwe;
    int u = 0;
    if (op == 0)
    {
        for (int i = qwe; i >= 0; i--)
        {
            if (a[u].nex[s[i] - '0'] == 0)
            {
                memset(a[cnt1].nex, 0, sizeof(a[cnt1].nex));
                a[cnt1].val = 0;
                a[u].nex[s[i] - '0'] = cnt1++;
            }
            u = a[u].nex[s[i] - '0'];
            a[u].val += infor;
        }
    }
    else
    {
        for (int i = qwe; i >= 0; i--)
        {
            if (b[u].nex[s[i] - '0'] == 0)
            {
                memset(b[cnt2].nex, 0, sizeof(b[cnt2].nex));
                b[cnt2].val = 0;
                b[u].nex[s[i] - '0'] = cnt2++;
            }
            u = b[u].nex[s[i] - '0'];
            b[u].val += infor;
        }
    }
}
void query()
{
    for (int cas = 0; cas < n; cas++)
    {
        int w = 0;
        int u1 = 0, u2 = 0;
        for (int i = qwe; i >= 0; i--)
        {
            if (a[a[u1].nex[0]].val && b[b[u2].nex[0]].val)
            {
                u1 = a[u1].nex[0];
                u2 = b[u2].nex[0];
                a[u1].val--;
                b[u2].val--;
            }
            else if (a[a[u1].nex[1]].val && b[b[u2].nex[1]].val)
            {
                u1 = a[u1].nex[1];
                u2 = b[u2].nex[1];
                a[u1].val--;
                b[u2].val--;
            }
            else if (a[a[u1].nex[0]].val && b[b[u2].nex[1]].val)
            {
                u1 = a[u1].nex[0];
                u2 = b[u2].nex[1];
                a[u1].val--;
                b[u2].val--;
                w += 1 << i;
            }
            else if (a[a[u1].nex[1]].val && b[b[u2].nex[0]].val)
            {
                u1 = a[u1].nex[1];
                u2 = b[u2].nex[0];
                a[u1].val--;
                b[u2].val--;
                w += 1 << i;
            }
        }
        ans[cas] = w;
    }
}
int main()
{
    //freopen("1.in", "r", stdin);
    //freopen("ans.txt", "w", stdout);
    int T;
    sc("%d", &T);
    while (T--)
    {
        init();
        sc("%d", &n);
        for (int i = 0; i < n; i++)
        {
            sc("%d", &t);
            for (int j = 0; j <= qwe; j++)
            {
                if (t & (1 << j))
                    s[j] = '1';
                else
                    s[j] = '0';
            }
            insert(s, 1, 0);
        }
        for (int i = 0; i < n; i++)
        {
            sc("%d", &t);
            for (int j = 0; j <= qwe; j++)
            {
                if (t & (1 << j))
                    s[j] = '1';
                else
                    s[j] = '0';
            }
            insert(s, 1, 1);
        }
        query();
        sort(ans, ans + n);
        for (int i = 0; i < n; i++)
            printf("%d%c", ans[i], i == n - 1 ? '\n' : ' ');
    }
}

6627 equation

有 n 个多项式 a_i*x+b_i ,求 |a_i*x+b_i|=C的所有解。

按照每个多项式的零点排序,然后依此枚举零点所在的范围,小于等于这个零点的多项式都是正数,否则就是负数。

特判一下无穷多解和无解的情况就可以了

#include 
#define ll long long
#define sc scanf
#define pr printf
#define Pair pair
using namespace std;
const int MAXN = 1e5 + 5;
struct node
{
	int a;
	int b;
	double chu;
}que[MAXN];
int gcd(int a, int b)
{
	return b == 0 ? a : gcd(b, a % b);
}
int main()
{
	int T;
	sc("%d", &T);
	while (T--)
	{
		vectorv;
		int n, C, len;
		sc("%d%d", &n, &C);
		for (int i = 1; i <= n; i++)
		{
			scanf("%d%d", &que[i].a, &que[i].b);
			que[i].chu = -(double)que[i].b / que[i].a;
		}
		sort(que + 1, que + n + 1, [](node q, node w) {
			return q.chu < w.chu;
		});
		for (int i = 1; i <= n; i++)
		{
			que[i].a += que[i - 1].a;
			que[i].b += que[i - 1].b;
		}
		for (int i = 0; i <= n; i++)//小于等于i的都是正数
		{
			// x = bb / aa
			int aa = que[i].a - (que[n].a - que[i].a);
			int bb = C - (que[i].b - (que[n].b - que[i].b));
			if (aa == 0 && bb == 0)//无穷多解
			{
				printf("-1\n");
				goto qwe;
			}
			else if (bb == 0)//唯一解
			{
				aa = 1;
			}
			else if (aa == 0)//无解
				continue;
			else//正常解
			{
				int g = gcd(aa, bb);
				aa /= g, bb /= g;
			}
			if (aa < 0)//分母符号一定为正
			{
				aa = -aa;
				bb = -bb;
			}
			//判ans范围
			if (i == 0)
			{
				if ((double)bb / aa <= que[1].chu)
					v.push_back(Pair{ bb,aa });
			}
			else if (i == n)
			{
				if ((double)bb / aa >= que[n].chu)
					v.push_back(Pair{ bb,aa });
			}
			else
			{
				if ((double)bb / aa >= que[i].chu && (double)bb / aa <= que[i + 1].chu)
					v.push_back(Pair{ bb,aa });
			}
		}
		v.erase(unique(v.begin(), v.end()), v.end());
		printf("%d", v.size());
		len = v.size();
		for (int i = 0; i < len; i++)
			printf(" %d/%d", v[i].first, v[i].second);
		printf("\n");
		qwe:;
	}
}

6628 permutation 1

枚举最后8个数字全排列。

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
int n, k;
struct node
{
    int aa[10];
}que[50005];
int a[10];
int main()
{
    int T;
    sc("%d", &T);
    while (T--)
    {
        sc("%d%d", &n, &k);
        if (n >= 9)
        {
            printf("%d ", n);
            for (int i = 1; i <= n - 9; i++)
                printf("%d ", i);
            for (int i = n - 8; i <= n - 1; i++)
                a[i - (n - 8) + 1] = i;
            int cnt = 0;
            do {
                for (int i = 1; i <= 8; i++)
                    que[cnt].aa[i] = a[i];
                cnt++;
            } while (next_permutation(a + 1, a + 1 + 8));
            sort(que, que + cnt, [](node q, node w) {
                for (int i = 1; i <= n; i++)
                    if (q.aa[i] - q.aa[i - 1] != w.aa[i] - w.aa[i - 1])
                        return q.aa[i] - q.aa[i - 1] < w.aa[i] - w.aa[i - 1];
            });
            for (int i = 1; i <= 8; i++)
                pr("%d%c", que[k - 1].aa[i], i == 8 ? '\n' : ' ');
        }
        else
        {
            for (int i = 1; i <= n; i++)
                a[i] = i;
            int cnt = 0;
            do {
                for (int i = 1; i <= n; i++)
                    que[cnt].aa[i] = a[i];
                cnt++;
            } while (next_permutation(a + 1, a + 1 + n));
            sort(que, que + cnt, [](node q, node w) {
                for (int i = 2; i <= n; i++)
                    if (q.aa[i] - q.aa[i - 1] != w.aa[i] - w.aa[i - 1])
                        return q.aa[i] - q.aa[i - 1] < w.aa[i] - w.aa[i - 1];
                });
            for (int i = 1; i <= n; i++)
                pr("%d%c", que[k - 1].aa[i], i == n ? '\n' : ' ');
        }
    }
}

6629 string matching

exkmp模板题

#include 
#define ll long long
#define sc scanf
#define pr printf
const ll mod = 998244353;
const int MAXN = 1e6 + 5;
using namespace std;
char x[MAXN];
int nex[MAXN];
int m;
void pre_EKMP() {
    nex[0] = m;
    int j = 0;
    while (j + 1 < m && x[j] == x[j + 1])j++;
    nex[1] = j;
    int k = 1;
    for (int i = 2; i < m; i++) {
        int p = nex[k] + k - 1;
        int L = nex[i - k];
        if (i + L < p + 1)nex[i] = L;
        else {
            j = max(0, p - i + 1);
            while (i + j < m && x[i + j] == x[j])j++;
            nex[i] = j;
            k = i;
        }
    }
}
int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%s", x);
        m = strlen(x);
        pre_EKMP();
        ll ans = 0;
        for (int i = 1; i < m; i++)
        {
            ans += min(nex[i] + 1, m - i);
        }
        printf("%lld\n", ans);
    }
}

6630 permutation 2

有一个长度为 n 的排列,求左端点和右端点已经确定的方案数。每个询问三个数字 n l r,表示排序长度为 n ,左端点为 l,右端点为 r,的排列的方案数。

首先他们是先下降在上升的序列,并且只有区间中间是可以交换的,并且每个数字只能交换一次。

假设输入是 10 3 7,那么他只有开区间 (4,6)是可以交换的,然后随便dp搞一下,

然后发现端点会使得区间长度加一,特判一下端点。

hdu 多校赛 第五场_第1张图片

#include 
#define ll long long
#define sc scanf
#define pr printf
const ll mod = 998244353;
using namespace std;
ll fib[100005];
int main()
{
	fib[1] = 1;
	fib[2] = 1;
	fib[3] = 1;
	for (int i = 4; i < 100005; i++)
		fib[i] = (fib[i - 1] + fib[i - 3]) % mod;
	int T;
	sc("%d", &T);
	while (T--)
	{
		int n, x, y;
		sc("%d%d%d", &n, &x, &y);
		int len = y - x - 1;
		if (x == 1)
			len++;
		if (y == n)
			len++;
		ll ans = fib[len];
		printf("%lld\n", ans);
	}
}

 

你可能感兴趣的:(2019,hdu,多校赛)