2022 ICPC 西安

https://codeforces.com/gym/104077

C. Clone Ranran

签到题

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

typedef long long LL;

	LL a, b, c;

LL divup(LL a, LL b){
	if(a % b == 0)
		return a / b;
	return a / b + 1;
}
	
void sol(){
	scanf("%lld%lld%lld", &a, &b, &c);
	
	int k = 0, s = 1;
	LL ans = c * b, tmp;
	do{
		k++;
		s <<= 1;
		
		tmp = k * a + divup(c, s) * b;
		ans = min(ans, tmp);
		
//		printf("k=%2d  s=%3lld  tmp=%lld\n", k, s, tmp);
		
	}while(s <= c);
	
	printf("%lld\n", ans);
//	printf("\n");
}

int main(){
//	freopen("data.in","r",stdin);
//	freopen("data.out","w",stdout);
	
	int T;
	scanf("%d", &T);
	while(T--)
		sol();

	return 0;

}

F. Hotel

签到题

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
void solve();
int main(){
	int T;T=1;
	while(T--)solve();
     return 0;
}
void solve(){
	int n;
	ll c1,c2,ans=0;
	string s;
	cin>>n>>c1>>c2;
	for(int i=1;i<=n;i++){
		cin>>s;
		int sum=0;
		if(s[0]==s[1]||s[0]==s[2]||s[1]==s[2])sum++;
		if(sum)
			ans+=c2+min(c2,c1);
		else ans+=min(c1,c2)*3;
     }if(c1*2<=c2){
		cout<<n*3*c1;
		return;
	}
	cout<<ans;
}

G. Perfect Word

分析:

很好想到对字符串按长度排序 (开始写错了就是因为按照字典序排序了)

依次考虑排序后的字符串

假如当前串为s[0,j]

如果s[0,j-1] 和 s[1,j] trie树中都出现过 那么我们将s[0,j]也加入trie树中

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=1e5+5;
int tr[maxn][27],tot,cnt,ans=0;
string s[maxn],t;
void ins(string ch) {                        
    int rt = 0;
    int len=ch.size();
    for (int i = 0; i < len; i++) {
        if (!tr[rt][ch[i] - 'a'])         
            tr[rt][ch[i] - 'a'] = ++tot;
        rt = tr[rt][ch[i] - 'a'];
    }
}
bool find(string s)      
{
    int rt=0;
    int len=s.size();
    for(int i=0;i<len;i++)
    {
        if(!tr[rt][s[i]-'a']) return false;   
        rt=tr[rt][s[i]-'a'];    
    }
    return true;
}
bool cmp(string aa,string bb){
	if(aa.size()!=bb.size())return aa.size()<bb.size();
	return aa<bb;
}
void solve();
int main(){
	int T;T=1;
	while(T--)solve();
     return 0;
}
void solve(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>t;
		if(t.size()==1)ins(t),ans=1;
		else s[++cnt]=t;
	} 
	sort(s+1,s+1+cnt,cmp);
	for(int i=1;i<=cnt;i++){
		int j=s[i].size();
		if(find(s[i].substr(1,j))&&find(s[i].substr(0,j-1)))
		ans=max(ans,j),ins(s[i]);
	}
	cout<<ans;
}

L. tree

分析

不知道是我们太菜了还是太卷了 这道题我们是费尽脑汁才做出来的

开始想的是树形dp 发现方程都设不出来

换个想法 那就硬搞 首先想到把最长链给找出来 然后依次找除去最大链的次大

这个可以用长链剖分

对于这些长度降序的链 一定保证相同长度的链与链之间的点不存在祖先关系

如果不是先找最大再找次大而是随意遍历的话就可能存在祖先关系

假如总共有cnt条链 然后遍历一遍 前i个用满足第一个条件 需要用i个 后面所有的满足第二个条件 需要用 len[i+1]个

对于每种情况取个min即可

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int N=1e6+5;
int n;
void solve();
void dfs(int,int);
bool cmp(int aa,int bb){
	return aa>bb;
}
vector<int>Q[N];
int ans[N];
int cnt;
int main(){
	int T;cin>>T;
	while(T--)solve();
     return 0;
}
int len[N], hson[N], top[N];
void dfs1(int p) {
    len[p] = 1;
    for (int i=0;i<Q[p].size();i++){
    	int q=Q[p][i];
            dfs1(q);
            if (len[q] + 1 > len[p])
                hson[p] = q, len[p] = len[q] + 1;
	}
        
}
void dfs2(int p, int tp) {
    top[p] = tp;
    if (hson[p]) dfs2(hson[p], tp);
    for (int i=0;i<Q[p].size();i++){
    	int q=Q[p][i];
        if (!top[q])
            dfs2(q, q);
	}
}
void cut() {
    dfs1(1);
    dfs2(1, 1);
}
void solve(){
	scanf("%d",&n);cnt=0;
	for(int i=1;i<=n;i++)Q[i].clear(),len[i]=hson[i]=top[i]=0;
	for(int i=2,x;i<=n;i++)scanf("%d",&x),Q[x].push_back(i);
	cut();
	for(int i=1;i<=n;i++)
	if(top[i]==i)ans[++cnt]=len[i];
	sort(ans+1,ans+1+cnt,cmp);
	int res=1e9+7;
	ans[cnt+1]=0;
	for(int i=0;i<=cnt;i++)
	res=min(res,i+ans[i+1]);
	cout<<res<<endl;
}

E. Find Maximum(待补)

分析

思路可能出现了问题 调了很久都没调出来

最后队友调处来了

#include<iostream>
using namespace std;
typedef long long ll;

ll f(ll x)
{
	if (x == 0)
		return 1;
	else if (x % 3 == 0)
		return f(x / 3) + 1;
	else
		return f(x - 1) + 1;
}
ll bacec = 0;//已有部分长度
ll bacec2 = 0;//最极端特例位置

int main()
{
	int T;
	cin >> T;
	for (int I = 0; I < T; I++)
	{
		ll l, r;
		cin >> l >> r;
		//sizes = 0;
		bacec = 0;//初始化多项式
		bacec2 = 0;
		ll m = 1;
		//找多项式,bacec-1就是关键值
		while (1)
		{
			//cout << bacec << "  ";
			if (bacec + m * 3 - 1 <= r)//需要扩大范围
			{
				m *= 3;
			}
			else
			{
				if (bacec + m * 2 - 1 < l)//在第二区内
				{
					//a[sizes] = m;
					//t[sizes] = 2;
					bacec += m * 2;
					//sizes++;//计入项
					m = 1;//m重置
					continue;//继续找下一项
				}
				else if (bacec + m * 2 - 1 >= l && bacec + m * 2 - 1 <= r)//跨过第二标志
				{
					//a[sizes] = m;
					//t[sizes] = 2;
					bacec += m * 2;
					//sizes++;//计入项
					m = 1;//m重置
					break;//结束
				}
				else if (bacec + m * 2 - 1 > r && bacec + m - 1 < l)//在第一区间
				{
					//a[sizes] = m;
					//t[sizes] = 1;
					bacec += m;
					//sizes++;//计入项
					m = 1;//m重置
					continue;//继续找下一项
				}
				else if (bacec + m - 1 >= l && bacec + m - 1 <= r)//跨过第一标志//有特例
				{
					//a[sizes] = m;
					//t[sizes] = 1;
					ll temp = bacec + m * 2 - 1 - m/3;//最极端特例
					bacec += m;
					//sizes++;//计入项
					m = 1;//m重置
					if (temp >= l && temp <= r)//如果极端特例可取
					{
						bacec2 = temp;
					}
					break;//结束
				}
			}
		}
		cout << max(f(bacec - 1), f(bacec2)) << "\n";
	}
}

B. Cells Coloring(待补)

分析:

很基础的网络流

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

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define fi first
#define se second

using ll = long long; using ull = unsigned long long; using pii = pair<int, int>;

template <typename A, typename B> bool smax(A &a, const B &b) { return a < b ? a = b, 1 : 0; }
template <typename A, typename B> bool smin(A &a, const B &b) { return b < a ? a = b, 1 : 0; }

constexpr int N = 250 * 2 + 2 + 7;
constexpr int M = 250 * 250 + 250 * 2 + 7;
constexpr int INF = INT_MAX;

int n, m, S, T, nod;
char s[N][N];
int sc[N], cl[N];

struct Edge {int to, ne, f;} g[M << 1]; int head[N], tot = 1;
void addedge(int x, int y, int z) { g[++tot].to = y; g[tot].f = z; g[tot].ne = head[x]; head[x] = tot; }
void adde(int x, int y, int z) { addedge(x, y, z); addedge(y, x, 0); }

int dis[N], gap[N], cur[N], q[N];
void bfs() {
    int hd = 0, tl = 0;
    q[++tl] = T, ++gap[dis[T] = 1];
    while (hd < tl) {
        int x = q[++hd];
        for fec(i, x, y) if (!dis[y] && g[i^1].f) dis[y] = dis[x] + 1, ++gap[dis[y]], q[++tl] = y;
    }
}
int dfs(int x, int a) {
    if (x == T || !a) return a;
    int flow = 0, f;
    for (int &i = cur[x]; i; i = g[i].ne)
        if (dis[x] == dis[g[i].to] + 1 && (f = dfs(g[i].to, std::min(a, g[i].f)))) {
            g[i].f -= f, g[i ^ 1].f += f;
            a -= f, flow += f;
            if (!a) return flow;
        }
    --gap[dis[x]];
    if (!gap[dis[x]]) dis[S] = nod + 1;
    ++gap[++dis[x]];
    return flow;
}
int ISAP() {
    static int ans = 0;
    bfs();
    while (dis[S] <= nod) memcpy(cur + 1, head + 1, sizeof(*head) * nod), ans += dfs(S, INF);
    return ans;
}

int main() {

    int c, d, mxk = 0, sum = 0;
    cin >> n >> m >> c >> d;
    for (int i = 1; i <= n; ++i) {
        cin >> (s[i] + 1);
        for (int j = 1; j <= m; ++j) s[i][j] = s[i][j] == '.', sc[i] += s[i][j], cl[j] += s[i][j], smax(mxk, cl[j]);
        smax(mxk, sc[i]), sum += sc[i];
    }

    S = n + m + 1, T = nod = S + 1;
    for (int i = 1; i <= n; ++i) adde(S, i, 0);
    for (int i = 1; i <= m; ++i) adde(i + n, T, 0);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j) if (s[i][j]) adde(i, j + n, 1);

    ll ans = LLONG_MAX;
    for (int k = 0; k <= mxk; ++k) {
        if (k) {
            memset(gap + 1, 0, sizeof(*gap) * nod);
            memset(dis + 1, 0, sizeof(*dis) * nod);
            for (int i = 1; i <= n; ++i) ++g[i * 2].f;
            for (int i = 1; i <= m; ++i) ++g[(i + n) * 2].f;
        }
        smin(ans, (ll)c * k + (ll)d * (sum - ISAP()));
    }
    cout << ans << '\n';

    return 0;
}
posted @ 2022-11-30 17:45  wzx_believer  阅读(754)  评论(0)    收藏  举报