zoukankan      html  css  js  c++  java
  • 【2021夏纪中游记】2021.7.17模拟赛

    2021.7.17模拟赛

    比赛概括:

    (mathrm{sum}=0+0+0+0)

    唉。

    T1 [JOI 2021 Final]有趣的家庭菜园 4:

    题目大意:

    思路:

    (mathcal{O}(n)) 求出需要浇水的前缀和和后缀和,枚举峰值,取最小的最大值即可。

    代码:

    const int N = 2e5 + 10;
    
    inline ll Read()
    {
    	ll x = 0, f = 1;
    	char c = getchar();
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') f = -f, c = getchar();
    	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    	return x * f;
    }
    
    int n;
    int a[N], b[N];
    ll sum1[N], sum2[N], ans = 1e18;
    
    int main()
    {
    	n = Read();
    	for (int i = 1; i <= n; i++) a[i] = Read();
    	for (int i = 2; i <= n; i++) b[i] = a[i] - a[i - 1];
    	for (int i = 2; i <= n; i++)
    	{if(b[i] <= 0) sum1[i] = -b[i] + 1; sum1[i] += sum1[i-1];}
    	for (int i = n; i >= 2; i--)
    	{if(b[i] >= 0) sum2[i] = b[i] + 1; sum2[i] += sum2[i+1];}
    	for (int k = 1; k <= n; k++)
    		ans = min(ans, max(sum1[k], sum2[k + 1]));
    	printf ("%lld
    ", ans);
    	return 0;
    }
    
    

    T2 [NOI2018]屠龙勇士:

    题目大意:

    思路:

    stoorz 爷精准押题。

    这题可以一眼看出是 ex-CRT:

    [left{egin{matrix} b_ix_i &equiv &a_ipmod{p_i} \ &vdots end{matrix} ight.]

    那么接下来题目有两个难点:

    1. 如何求出每条龙对应哪把剑。
    2. (p_i) 不是质数,所以 (b_i) 不能求逆元,该如何处理。

    第一点,可以通过平衡树、权值线段树等维护。这里也可以偷懒用 multiset

    第二点要剖析 ex-CRT 的本质。详见 emptyset 的博客

    代码:

    const int N = 1e5 + 10;
    
    inline ll Read()
    {
    	ll x = 0, f = 1;
    	char c = getchar();
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') f = -f, c = getchar();
    	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    	return x * f;
    }
    
    int t, n, m;
    ll a[N], p[N];
    int b[N], val[N];
    
    ll exgcd(ll a, ll b, ll &x, ll &y)
    {
    	if (!b)
    	{
    		x = 1, y = 0;
    		return a;
    	}
    	ll gcd = exgcd(b, a % b, y, x);
    	y -= a / b * x;
    	return gcd;
    }
    
    ll qpow(ll a, ll b, ll mod)
    {
    	ll ans = 1;
    	for (; b; b >>= 1, a = a * a % mod)
    		if (b & 1) ans = ans * a % mod;
    	return ans;
    }
    
    ll mul(ll a, ll b, ll mod)
    {
    	ll ans = 0;
    	for (; b; b >>= 1, a = (a + a) % mod)
    		if (b & 1) ans = (ans + a) % mod;
    	return ans;
    }
    
    ll mx;
    multiset <ll> s;
    
    int main()
    {
    	for (int t = Read(); t--; )
    	{
    		s.clear();
    		n = Read(), m = Read(); mx = 0;
    		for (int i = 1; i <= n; i++) a[i] = Read();
    		for (int i = 1; i <= n; i++) p[i] = Read();
    		for (int i = 1; i <= n; i++) val[i] = Read();
    		for (int i = 1; i <= m; i++) s.insert(Read());
    		
    		for (int i = 1; i <= n; i++)
    		{
    			multiset<ll>::iterator u = s.upper_bound(a[i]);
    			if (u != s.begin()) u--;
    			b[i] = *u;
    			s.erase(u);
    			s.insert(val[i]); // b[i]x > a[i]
    			mx = max(mx, (ll)ceil((double)a[i] / b[i]));
    		}
    		bool HasSolution = 1;
    		
    		ll lcm = 1, ans = 0;
    		for (int i = 1; i <= n; i++)
    		{
    			ll x, y, gcd = exgcd(lcm * b[i] % p[i], p[i], x, y), A = ((a[i] - b[i] * ans % p[i]) % p[i] + p[i]) % p[i];
    			x = (x % p[i] + p[i]) % p[i];
    			if (A % gcd) {puts("-1"); HasSolution = 0; break;}
    			ans = (ans + mul(A / gcd, x, p[i] / gcd) * lcm % (lcm *= p[i] / gcd)) % lcm;
    		}
    		if(!HasSolution) continue;
    		if (mx > ans) ans = ans + (ll)ceil((double)(mx - ans) / lcm) * lcm;
    		printf ("%lld
    ", ans);
    		
    	}
    	return 0;
    }
    

    T3 周长:

    题目大意:

    小PP喝饮料中了大奖,奖励n块宽度为1的农田,每一块都有自己的长度,小PP可以自己去选择这N块农田的位置,要按如图的方式拼接在一起。每块农田互不相同(即使长度一样也不同)那么显然有n!种放置方法。不同的方法可以使整个大农田的周长不同,如图(a)周长为16,而图(b)的周长为20.可证明没有比20 更大的周长存在。小PP喜欢绕着农田跑步,他希望最终这个大农田的周长最大。

    正文:

    考虑状压 DP。设 (f_{i,j},g_{i,j}) 分别表示状态 (i) 当前第 (j) 个块的最大周长及其方案数。转移显然。

    代码:

    const int N = 20, M = 4e4 + 10;
    
    inline ll Read()
    {
    	ll x = 0, f = 1;
    	char c = getchar();
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') f = -f, c = getchar();
    	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    	return x * f;
    }
    
    int n, a[N]; 
    ll f[M][N], g[M][N], ans, cnt;
    
    int main()
    {
    	n = Read();
    	for (int i = 1; i <= n; i++) a[i] = Read();
    	for (int i = 1; i <= n; i++) f[1 << i-1][i] = 2 * a[i], g[1 << i-1][i] = 1;
    	for (int k = 0; k < (1 << n); k++)
    		for (int i = 1; i <= n; i++)
    			if ((k >> i-1) & 1)
    				for (int j = 1; j <= n; j++)
    					if(!((k >> j-1) & 1))
    					{
    						if (f[k | (1 << j-1)][j] < f[k][i] + (a[j] - min(a[i], a[j])) * 2)
    							f[k | (1 << j-1)][j] = f[k][i] + (a[j] - min(a[i], a[j])) * 2, 
    							g[k | (1 << j-1)][j] = g[k][i];
    						else if (f[k | (1 << j-1)][j] == f[k][i] + (a[j] - min(a[i], a[j])) * 2)
    							g[k | (1 << j-1)][j] += g[k][i];
    					}
    	
    	for (int i = 1; i <= n; i++)
    		if (ans < f[(1 << n) - 1][i] + n * 2) ans = f[(1 << n) - 1][i] + n * 2, cnt = g[(1 << n) - 1][i];
    		else if (ans == f[(1 << n) - 1][i] + n * 2) cnt += g[(1 << n) - 1][i];
    	
    	printf ("%lld %lld
    ", ans, cnt);
    	return 0;
    }
    

    T4 [ROIR 2018 Day1]管道监控:

    题目大意:

    正文:

    恶心。

    线性规划问题。可以先用 trie 树求解出所有路经的最小花费。考虑建边:

    • 源点向根节点连流量 (+infty)、费用 (0) 的边。
    • 叶子节点向汇点连流量 (1)、费用 (0) 的边。
    • 节点 (i) 向父亲连一条流量叶子数减一、费用 (0) 的边;父亲再连向 (i) 流量为 (+infty) 费用 (0) 的边。
    • 如果当前点是某单词的结尾,向开头连流量 (1)、费用 (w) 的边。

    由于这个图已经不是 DAG,求增广路时就可以用双端队列。

    代码:

    const int N = 510, M = 1e6 + 10;
    const ll inf = 1e18;
    
    inline ll Read()
    {
    	ll x = 0, f = 1;
    	char c = getchar();
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') f = -f, c = getchar();
    	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    	return x * f;
    }
    
    int n, m, t;
    int fa[N], siz[N];
    char c[N], s[M];
    
    int S, T;
    struct edge
    {
    	ll to, w, val, nxt, id;
    }e[M << 1];
    int head[N], tot = 1;
    
    void add(int u, int v, ll w, ll val, int id = 0)
    {
    	e[++tot] = (edge) {v, w, val, head[u], id}, head[u] = tot;
    	e[++tot] = (edge) {u, 0, -val, head[v], id}, head[v] = tot;
    }
    
    struct Trie
    {
    	ll tot, t[M][30], val[M], id[M];
    	Trie() { memset (val, 0x3f3f3f3f, sizeof val), tot = 1;}
    	
    	void Insert(char *s, ll cst, ll k)
    	{
    		ll p = 1, len = strlen (s + 1);
    		for (int i = len; i; i--)
    		{
    			if (!t[p][s[i] - 'a']) t[p][s[i] - 'a'] = ++tot;
    			p = t[p][s[i] - 'a'];
    		}
    		if (val[p] > cst) val[p] = cst, id[p] = k;
    	}
    	
    	void Add(int x)
    	{
    		ll p = 1;
    		for (ll u = x; fa[u]; u = fa[u])
    		{
    			if (!t[p][c[u] - 'a']) break;
    			p = t[p][c[u] - 'a'];
    			if (val[p] < inf) add(fa[u], x, 1, val[p], id[p]);
    		}
    	}
    }tr;
    
    int pre[N];
    bool vis[N];
    ll dis[N], incf;
    deque <int> q;
    bool SPFA()
    {
    	memset (dis, 0x3f3f3f3f, sizeof dis);
    	while (!q.empty()) q.pop_front();
    	q.push_back(S);
    	vis[S] = 1; dis[S] = 0;
    	while (!q.empty())
    	{
    		int u = q.front(); q.pop_front();
    		vis[u] = 0;
    		for (int i = head[u]; ~i; i = e[i].nxt)
    		{
    			int v = e[i].to;
    			if (dis[v] > dis[u] + e[i].val && e[i].w)
    			{
    				dis[v] = dis[u] + e[i].val;
    				pre[v] = i;
    				if (!vis[v]) 
    				{
    					vis[v] = 1;
    					if (q.size() && dis[v] <= dis[q.front()]) q.push_front(v);
    					else q.push_back(v);
    				}
    			} 
    		}
    	}
    	return dis[T] < inf;
    }
    
    
    ll cost, maxFlow;
    void MCMF()
    {
    	cost = 0;
    	while (SPFA())
    	{
    		int u = T; incf = inf;
    		for (; u != S; u = e[pre[u] ^ 1].to)
    			incf = min(incf, e[pre[u]].w);
    			
    		cost += dis[T] * incf, maxFlow -= incf;
    		for (u = T; u != S; u = e[pre[u] ^ 1].to)
    			e[pre[u]].w -= incf,
    			e[pre[u] ^ 1].w += incf;
    	}
    	return ;
    }
    
    
    int main()
    {
    	memset (head, -1, sizeof head);
    	n = Read(), m = Read(), t = Read() ^ 1;
    	S = N - 1, T = N - 2;
    	for (int i = 2; i <= n; i++)
    	{
    		fa[i] = Read();
    		for(c[i] = getchar(); !('a' <= c[i] && c[i] <= 'z'); c[i] = getchar()); 
    		siz[i] = 1, siz[fa[i]] = 0;
    	}
    	add(S, 1, inf, 0);
    	for (int i = 1; i <= n; i++)
    	{
    		if (!siz[i]) continue;
    		add(i, T, 1, 0); maxFlow++;
    	}
    	for (int i = n; i; i--)
    	{
    		add(fa[i], i, siz[i] - 1, 0);
    		add(i, fa[i], inf, 0);
    		siz[fa[i]] += siz[i];
    	}
    	for (int i = 1; i <= m; i++)
    	{
    		ll val = Read();
    		scanf ("%s", s + 1);
    		tr.Insert(s, val, i);
    	}
    	for (int i = 1; i <= n; i++) tr.Add(i);
    	
    		
    	MCMF();
    	
    	if (maxFlow) {puts("-1"); return 0;}
    	
    	printf ("%lld
    ", cost);
    	
    	if (t) return 0;
    	
    	cost = 0;
    	for (int i = 2; i <= tot; i += 2)
    		if (!e[i].w && e[i].id) cost ++;
    	printf ("%lld
    ", cost);
    	
    	for (int i = 2; i <= tot; i += 2)
    		if (!e[i].w && e[i].id) 
    			printf ("%d %d %d
    ", e[i ^ 1].to, e[i].to, e[i].id);
    	return 0;
    }
    
    
  • 相关阅读:
    StrToUnicode C#语言如何将汉字转换成Unicode字符
    SQLServer 2008数据库查看死锁、堵塞的SQL语句
    String.IsNullOrEmpty和"".length>0 那个更高效
    使用策略设计模式,反射,解决商城系统中的商品折扣问题
    假分页
    MAC校验
    eclipse环境加载svn
    将数据导出Excel格式
    svn提交问题
    字符串前拼接字符
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/15028596.html
Copyright © 2011-2022 走看看