SDNU ACM-ICPC 2020 Competition For the End of Term(11-29)【解题报告】

前言

\quad 今天出了一坨锅,原因是出题组人手不够(没人验题…,求轻喷

说明

\quad 以下内容为现场赛时写的,一边看榜,一边写,所以是按照每道题被拿走FB的顺序写的。

题解

1644.Euler YYDS![找规律]

出题人:lhr \quad 验题人:ymf

\quad 全场最简单的题目,于 00:15:10Visiter 拿走全场 First Blood

题目大意

\quad T    ( 1 ≤ T ≤ 10 ) T\;(1 \leq T \leq 10) T(1T10) 组数据,每组给一个整数 n    ( 1 ≤ n ≤ 1 0 100 ) n\;(1 \leq n \leq 10^{100}) n(1n10100),问 φ ( n ) \varphi(n) φ(n) 的奇偶性.

分析

\quad 找规律可知:当 n ≥ 3 n \geq 3 n3 φ ( n ) \varphi(n) φ(n) 恒为偶数.

\quad 可使用更相减损之术: gcd ⁡ ( x , n ) = g c d ( n − x , n ) \gcd(x, n) = gcd(n - x, n) gcd(x,n)=gcd(nx,n) 简单证明.

代码实现
#include <bits/stdc++.h>
using namespace std;

const int M = (int)1e2;

char n[M + 5];

void work()
{
	scanf("%s", n);
	puts(strcmp(n, "1") == 0 || strcmp(n, "2") == 0 ? "odd" : "even");
}

int main()
{
	// freopen("3.in", "r", stdin);
	// freopen("3.out", "w", stdout);
	int T; scanf("%d", &T);
	while(T--) work();
	return 0;
}

1649.Palindrome of prime number[模拟 + 暴力判断质数]

出题人:wx \quad 验题人:lhr

\quad 00:19:41 FB 诞生,By:18XiWenjuan

题目大意

T    ( 1 ≤ T ≤ 1 0 5 ) T\;(1 \leq T \leq 10^5) T(1T105) 组数据,每组一个质数 n    ( 1 ≤ n ≤ 1 0 5 ) n\;(1 \leq n \leq 10^5) n(1n105),问 n n n 的回文数是否是质数.

分析

\quad 直接模拟 + 暴力循环 $[1, \sqrt{n}] $ 判断,事实证明这样不会 TLE.

代码实现
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

char n[20];

bool is_prime(ll n)
{
    for(int i = 2; 1ll * i * i <= n; ++i)
    {
        if(n % i == 0) return 0;
    }
    return 1;
}

void work()
{
    scanf("%s", n);
    int len = strlen(n);
    for(int i = len; i < 2 * len - 1; ++i) n[i] = n[2 * len - i - 2];
    ll m = 0;
    for(int i = 0; i < 2 * len - 1; ++i) m = m * 10 + n[i] - '0';
    puts(is_prime(m) ? "prime" : "noprime");
}

int main()
{
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
    int T; scanf("%d", &T);
    while(T--) work();
    return 0;
}

1652.The Magic LMR Ring[找规律]

出题人:lhr \quad 验题人:

\quad 00:57:30 FB 诞生,By:2019jiyi

题目大意

\quad 求解大小为 n n n,间隔为 1 1 1 的约瑟夫环.

分析

\quad 找规律可得

n123456789101112131415
答案113135713579111315

\quad 答案显然.

\quad 证明:

\qquad f ( n ) f(n) f(n) 为大小为 n n n,间隔为 1 1 1 约瑟夫环的答案.

\qquad n n n 为偶数时

在这里插入图片描述

\qquad 删完一圈后发现,答案为 2 f ( n / 2 ) − 1 2f(n / 2) - 1 2f(n/2)1.

在这里插入图片描述

\qquad n n n 为奇数时

在这里插入图片描述

\qquad 删完一圈后发现,答案为 2 f ( n / 2 ) + 1 2f(n / 2) + 1 2f(n/2)+1.

在这里插入图片描述

\qquad 分析到这里,使用递归即可 A C AC AC.

\qquad 剩下的部分留给读者自行证明.

代码实现

\quad 2019jiyiの代码

#include <queue>
#include <vector>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
typedef long long ll;
using namespace std;

int main()
{
    int t;
    scanf("%d",&t);
    for (int i=1;i<=t;i++)
    {
        ll n;
        scanf("%lld",&n);
        ll x=2;
        while(x<=n)
        {
            x*=2;
        }
        x/=2;
        ll y=n-x;
        if(y==0) cout << 1 << endl;
        else cout << y*2+1 << endl;
    }
    return 0;
}

\quad 2020lihaoranの代码

#include <bits/stdc++.h>
using namespace std;

int f(int n)
{
    if(n <= 2) return 1;
    if(n & 1)  return 2 * f(n / 2) + 1;
    else       return 2 * f(n / 2) - 1;
}

void work()
{
    int n; scanf("%d", &n);
    printf("%d\n", f(n));
}

int main()
{
    int T; scanf("%d", &T);
    while(T--) work();
    return 0;
}

1654.Treasure House[BFS + 记录路径]

出题人:lhr \quad 验题人:

\quad 00:38:22 FB 诞生,By:19zhanglikun

题目大意

\quad 给一张 n × m n \times m n×m 的地图,$’$’$ 可走, ′ # ′ '\#' # 不可走,求从 ( 1 , 1 ) (1,1) (1,1) 点出发到 ( n , m ) (n,m) (n,m) 的最短路径,若最短路径不唯一求字典序最大的路径.

分析

\quad 模板题,无需分析.

代码实现
#include <bits/stdc++.h>
using namespace std;

int n, m;
char s[15][15];
int step[15][15];
int pre[15][15];

int dx[] = {0, 1, -1, 0};
int dy[] = {-1, 0, 0, 1};

struct node
{
    int x, y;
    node(int _x = 0, int _y = 0): x(_x), y(_y){}
};

queue<node> q;

void bfs(int x, int y)
{
    memset(step, -1, sizeof(step));
    memset(pre, -1, sizeof(pre));

    step[x][y] = 0;
    q.push(node(x, y));

    node u, v;
    while(!q.empty())
    {
        u = q.front(); q.pop();
        if(u.x == n && u.y == m) return;
        for(int i = 0; i < 4; ++i)
        {
            v.x = u.x + dx[i];
            v.y = u.y + dy[i];
            if(v.x < 1 || v.x > n || v.y < 1 || v.y > m) continue;
            if(s[v.x][v.y] == '#' || ~step[v.x][v.y]) continue;
            step[v.x][v.y] = step[u.x][u.y] + 1;
            pre[v.x][v.y] = i;
            q.push(v);
        }
    }
}

stack<char> st;

void work()
{
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; ++i) scanf("%s", s[i] + 1);
    bfs(1, 1);
    printf("%d\n", step[n][m]);
    int x = n, y = m;
    while(x != 1 || y != 1)
    {
        if(pre[x][y] == 0)      st.push('W'), ++y;
        else if(pre[x][y] == 1) st.push('S'), --x;
        else if(pre[x][y] == 2) st.push('N'), ++x;
        else if(pre[x][y] == 3) st.push('E'), --y;

    }
    while(!st.empty())
    {
        putchar(st.top());
        st.pop();
    }
    printf("\n");
}

int main()
{
    work();
    return 0;
}

1653.The number of Invertion[逆序对模板题]

出题人:ryc \quad 验题人:lhr

\quad 再次被 18XiWenjuan00:40:57 拿走 First Blood

题目大意

\quad 求逆序对.

分析

\quad 大一不会的可以趁这个机会学习一下.

\quad 大二不会的可以重修了.

代码实现
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int M = (int)1e6;
const int mod = (int)1e8 + 7;

int n;
ll a[M + 5];
ll b[M + 5];

ll merge_sort(ll a[], int l, int r)
{
    if(l >= r) return 0;
    int mid = (l + r) >> 1; ll cnt = (merge_sort(a, l, mid) + merge_sort(a, mid + 1, r)) % mod;
    int i = l, j = mid + 1, k = 0;
    while(i <= mid && j <= r) if(a[i] <= a[j]) b[++k] = a[i++]; else b[++k] = a[j++], (cnt += mid - i + 1) %= mod;
    while(i <= mid) b[++k] = a[i++];
    while(j <= r)   b[++k] = a[j++];
    for(int i = l, j = 1; i <= r; ++i, ++j) a[i] = b[j];
    return cnt;
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
    printf("%lld\n", merge_sort(a, 1, n));
    return 0;
}

1647.L Sequence[模拟]

出题人:lhr \quad 验题人:ymf

\quad 01:40:05 又 被 19zhanglikun 拿走 FB

题目大意

\quad 无需多言.

分析

\quad 直接模拟.

代码实现
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

int m;
ll f[100];
ll s[100];
int pw[20];

int cal(ll n)
{
	int c = 0;
	while(n)
	{
		++c;
		n /= 10;
	}
	return c;
}

void init()
{
	f[1] = f[2] = 1; s[1] = 1, s[2] = 2;
	for(int i = 3; i <= 90; ++i)
	{
		f[i] = f[i - 2] + f[i - 1];
		s[i] = s[i - 1] + cal(f[i]) * f[i];
		if(s[i] > (int)1e9)
		{
			m = i;
			break;
		}
	}

	pw[0] = 1;
	for(int i = 1; i <= 9; ++i) pw[i] = pw[i - 1] * 10;
}

void work()
{
	int n; scanf("%d", &n);
	int p = 1; while(s[p] < n) ++p;
	n -= s[p - 1];
	int len = cal(f[p]);
	n = (n - 1) % len + 1;
	printf("%d\n", f[p] / pw[len - n] % 10);
}

int main()
{
	// freopen("input.txt", "r", stdin);
	// freopen("output.txt", "w", stdout);
	init();
	int T; scanf("%d", &T);
	while(T--) work();
	return 0;
}

1648.Min. Min? Min![差分思想]

出题人:lhr \quad 验题人:

\quad 02:44:22 又 被 19zhanglikun 拿走 FB

题目大意

\quad 前缀取min + 后缀取min.

分析

\quad 看代码就懂了.

代码实现
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int M = (int)1e6;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const ll mod = (ll)1e9 + 7;

int n, m;
unsigned long long k1, k2;
ll a[M + 5];
ll d[3][M + 5];

inline unsigned long long read(const long long& l, const long long& r)
{
	unsigned long long k3 = k1, k4 = k2;
	k1 = k4;
	k3 ^= k3<<23;
	k2 = k3^k4^(k3>>17)^(k4>>26);
	return (k2 + k4) % (r - l + 1) + l;
}

void work()
{
	scanf("%d %d %llu %llu", &n, &m, &k1, &k2);
	for(int i = 1; i <= n; ++i)
	{
		a[i] = read(1ll, (ll)1e18);
		d[1][i] = d[2][i] = inf;
	}

	int op, p; ll x;
	while(m--)
	{
		op = read(1, 2); p = read(1, n); x = read(1ll, (ll)1e18);
		d[op][p] = min(d[op][p], x);
	}

	for(int i = n - 1; i >= 1; --i) d[1][i] = min(d[1][i], d[1][i + 1]);
	for(int i = 2; i <= n; ++i)     d[2][i] = min(d[2][i], d[2][i - 1]);
	for(int i = 1; i <= n; ++i)     a[i] = min(a[i], min(d[1][i], d[2][i]));

	ll ans = 0;
	for(int i = 1; i <= n; ++i) ans = (ans + a[i]) % mod;
	printf("%lld\n", ans);
}

int main()
{
	// freopen("input.txt", "r", stdin);
	// freopen("output.txt", "w", stdout);
	work();
	// cerr << 1.0 * clock() / CLOCKS_PER_SEC << endl;
	return 0;
}

1656.Changing a Character[?]

出题人:? \quad 验题人:?
题目大意

\quad

分析

\quad

代码实现

\quad

1646.Extraordinary Permutation[单调栈 + 算贡献 + 费马小定理]

出题人:lhr \quad 验题人:

03:24:50 又又 被 19zhanglikun 拿走 FB

题目大意

\quad 给一个排列 P P P,求 P P P 所有总区间最大值除以最小值的乘积,答案对 998244353 998244353 998244353 取模.

分析

\quad 计算每个值当最大值和最小值的贡献.

\quad 单调栈维护每个数的最大值和最小值区间.

代码实现
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int M = (int)1e5;
const ll mod = (ll)998244353;

int n, p[M + 5];
int st[M + 5], tp;
int L[M + 5], R[M + 5];

ll quick(ll a, ll b, ll p = mod)
{
	a %= p;
	ll s = 1;
	while(b)
	{
		if(b & 1) s = s * a % p;
		a = a * a % p;
		b >>= 1;
	}
	return s % p;
}

ll inv(ll n, ll p = mod)
{
	return quick(n, p - 2, p);
}

void work()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) scanf("%d", &p[i]);

	ll ans = 1;

	/** 计算 Min 的贡献 **/
	tp = 0;
	for(int i = 1; i <= n; ++i)
	{
		while(tp && p[st[tp]] > p[i]) --tp;
		if(tp)	L[i] = st[tp] + 1;
		else	L[i] = 1;
		st[++tp] = i;
	}

	tp = 0;
	for(int i = n; i >= 1; --i)
	{
		while(tp && p[st[tp]] > p[i]) --tp;
		if(tp)	R[i] = st[tp] - 1;
		else	R[i] = n;
		st[++tp] = i;
	}

	for(int i = 1; i <= n; ++i)
	{
		ans = ans * quick(p[i], 1ll * (i - L[i] + 1) * (R[i] - i + 1)) % mod;
		assert(0 <= ans && ans < mod);
	}


	/** 计算 Max 的贡献 **/
	tp = 0;
	for(int i = 1; i <= n; ++i)
	{
		while(tp && p[st[tp]] < p[i]) --tp;
		if(tp)	L[i] = st[tp] + 1;
		else	L[i] = 1;
		st[++tp] = i;
	}

	tp = 0;
	for(int i = n; i >= 1; --i)
	{
		while(tp && p[st[tp]] < p[i]) --tp;
		if(tp)	R[i] = st[tp] - 1;
		else	R[i] = n;
		st[++tp] = i;
	}

	for(int i = 1; i <= n; ++i)
	{
		ans = ans * inv(quick(p[i], 1ll * (i - L[i] + 1) * (R[i] - i + 1))) % mod;
		assert(0 <= ans && ans < mod);
	}

	assert(0 <= ans && ans < mod);
	printf("%lld\n", ans);
}

int main()
{
	// freopen("input.txt", "r", stdin);
	work();
	return 0;
}

1651.Team A is better or Team B is better[DFS + 计算贡献]

出题人:ymf \quad 验题人:lhr

04:18:41 又又又 被 19zhanglikun 拿走 FB

题目大意

\quad 2 n 2n 2n 个人,每对人之间有一个攻击值,要求你给这 2 n 2n 2n 个人两两分组使得两组的攻击值最大.

分析

\quad D F S DFS DFS 暴搜,在搜索的过程中计算贡献.

代码实现
#include <bits/stdc++.h>
using namespace std;

typedef long  long ll;

int n;
int g[30][30];
int a[30], alen;
int b[30], blen;

ll mx;

void dfs(int u, int alen, int blen, ll s)
{
    if(u == n + 1)
    {
        mx = max(mx, s);
        return;
    }
    if(alen < n / 2)
    {
        a[alen + 1] = u;
        ll t = s;
        for(int i = 1; i <= blen; ++i) t += g[u][b[i]];
        dfs(u + 1, alen + 1, blen, t);
    }
    if(blen < n / 2)
    {
        b[blen + 1] = u;
        ll t = s;
        for(int i = 1; i <= alen; ++i) t += g[a[i]][u];
        dfs(u + 1, alen, blen + 1, t);
    }
}

void work()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= n; ++j)
            scanf("%d", &g[i][j]);
    dfs(1, 0, 0, 0);
    printf("%lld\n", mx);
}

int main()
{
    work();
    return 0;
}

1643.Balanced Number[数位DP + 三进制压缩]

出题人:ryc \quad 验题人:lhr
题目大意

\quad 求区间 [ A , B ] [A, B] [A,B] 中有多少个数,数位上有偶数个偶数,奇数个奇数.

分析

\quad 大二的估计一看涉及知识就懂了.

代码实现
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

int num[20];
ll f[20][60000];

bool check(int n)
{
	if(n == 0) return 0;
	for(int i = 9, t; i >= 0; --i)
	{
		t = n % 3;
		if((i&1) && t == 2 || !(i&1) && t == 1) return 0;
		n /= 3;
	}
	return 1;
}

int cal_state(int cur, int x)
{
	int num[10];
	for(int i = 9; i >= 0; --i)
	{
		num[i] = cur % 3;
		cur /= 3;
	}
	if(num[x] == 0) 	 num[x] = 1;
	else if(num[x] == 1) num[x] = 2;
	else if(num[x] == 2) num[x] = 1;
	cur = 0;
	for(int i = 0; i <= 9; ++i) cur = cur * 3 + num[i];
	return cur;
}

ll dfs(int pos, int state, bool leading, bool limit)
{
	if(pos == -1) return check(state);
	if(!limit && ~f[pos][state]) return f[pos][state];
	ll res = 0; int up = (limit ? num[pos] : 9);
	for(int i = 0; i <= up; ++i)
	{
		res += dfs(pos - 1, leading && i == 0 ? 0 : cal_state(state, i), 
					leading && i == 0, limit && i == up);
	}
	if(!limit) f[pos][state] = res;
	return res;
}

ll cal(ll n)
{
	if(n == 0) return 0;
	int pos = 0;
	while(n)
	{
		num[pos++] = n % 10;
		n /= 10;
	}
	return dfs(pos - 1, 0, 1, 1);
}

void work()
{
	ll l, r; scanf("%lld %lld", &l, &r);
	printf("%lld\n", cal(r) - cal(l - 1));
}

int main()
{
	memset(f, -1, sizeof(f));
	int T; scanf("%d", &T);
	while(T--) work();
	return 0;
}

1650.Perfect Sudoku[跳舞链 || 爆搜 + 剪枝]

出题人:syh \quad 验题人:lhr、ymf
题目大意

\quad 2 2 2 阶数独有多少种状态答案唯一.

分析

\quad 俺只会爆搜…

代码实现

\quad 代码就不贴了.

吐槽

  1. 1002题 1 ≤ n ≤ 1 0 100 1 \leq n \leq 10^{100} 1n10100,居然还有人暴力枚举,头真铁啊!

  2. 暴躁老哥上线

在这里插入图片描述

END

所以说,知道自己的真实实力最重要,不要因为一时的失败就觉得自己不行。

一定要多试几次你才会知道,自己真的不行。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值