The 2022 ICPC Asia Xian Regional Contest(2022西安站)

J

Strange Sum

题意:给定长度为n的数组,从中选择元素(可以不选),若选择元素ai,则每个长度为i的区间内至多只能选择2个元素。

思路:设我们选择下标最大的元素a[p],那么[1,p]区间内也最多只能选2个。所以我们最多只能选2个。

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define PII pair<int,int>
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;

using namespace std;
int n;
int a[N];
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);
    cout<<max({a[n],a[n]+a[n-1],0})<<'\n';
}
signed main()
{
    //ios;
    int _t=1;
    //cin>>_t;
    while(_t--) solve();
    system("pause");
    return 0;
}

C

Clone Ranran

题意:给定a,b,c。有c道题需要做,有两种操作,(1)克隆自己,花费a分钟。(2)解决一道题,花费b分钟。问最少需要多少分钟做完。

思路:c<=1e9.最多克隆30次。枚举克隆次数

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define PII pair<int,int>
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;

using namespace std;
ll a,b,c;
void solve()
{
    cin>>a>>b>>c;
    ll ans=1e18;
    for(int i=0;i<=30;i++)
    {
        ll t=1<<i;
        ll tem=(c+t-1)/t;
        ans=min(ans,a*i+tem*b);
    }
    cout<<ans<<'\n';
}
signed main()
{
    //ios;
    int _t=1;
    cin>>_t;
    while(_t--) solve();
    system("pause");
    return 0;
}

Hotel

 题意:有n只3人队伍,酒店中单人间的价格是c1,双人间的价格是c2.每间房间只能入住同一只队伍且性别相同的人。问最少花费。

思路:模拟

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define PII pair<int,int>
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;

using namespace std;
int n,c1,c2;
void solve()
{
	cin>>n>>c1>>c2;
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		string s;
		cin>>s;
		if(s[0]==s[1]||s[0]==s[2]||s[1]==s[2])
		{
			ans+=min(c2,2*c1);
			ans+=min(c1,c2);
		}
		else
		{
			ans+=min(3*c1,3*c2);
		}
	}
	cout<<ans<<'\n';
}
signed main()
{
	//ios;
	int _t=1;
	//cin>>_t;
	while(_t--) solve();
	system("pause");
	return 0;
}

G

Perfect Word

题意:给定n个字符串。一个字符串s称为good当且仅当s的所有子串全都是给定的字符串。问最长的good串的长度。

思路:一个串s[1]s[2]...s[n]称为good,当且仅当以下两个串都是good的。

s[1]s[2]...s[n-1]

s[2]s[3]...s[n]

我们可以先把字符串按长度排序,然后判断每个串是否是good的,是我们就把它放到set中。

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define PII pair<int,int>
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;

using namespace std;
int n;
set<string>S;
string t[N];
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>t[i];
	sort(t+1,t+n+1,[](const string &a,const string &b){return a.size()<b.size();});
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		if(t[i].size()==1||(S.count(t[i].substr(0,t[i].length()-1))&&S.count(t[i].substr(1))))
		{
			S.insert(t[i]);
			ans=max(ans,(int)t[i].length());
		}
	}
	cout<<ans<<'\n';
}
signed main()
{
	//ios;
	int _t=1;
	//cin>>_t;
	while(_t--) solve();
	system("pause");
	return 0;
}

L

Tree

题意:给定一棵以1为根的树,将这棵树划分成若干个集合,满足在每个集合内,要么任意两点间存在祖先关系,要么任意两点间都没有祖先关系。

思路:每个集合要么是一条链,要么是不同子树中的许多点。

长链剖分

显然我们选一条链作为一个集合时,那么将这条链取到叶子是最优的。

设我们长链剖分得到p条链,每条链的长度为pl[i]

当我们全用第二种集合来划分时,那么答案即为树的最大深度。这个答案也可以看成将所有链起点水平放置,同一行中的点划分成一个集合。答案也就是最长链的长度。

再考虑选择一些长链作为第一种集合,因为第二类集合的答案是 剩余链中的最大长度,所以第一类集合选择最长的链最优。

我们将所有链按长度从大到小排序。枚举我们选择前i条链作为第一类集合,剩余的作为第二类集合,那么答案就是max(i+lp[i+1]) 

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define PII pair<int,int>
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;

using namespace std;
int n;
vector<int>g[N],lp;
int son[N],len[N];
void dfs1(int u)
{
    for(int v:g[u])
    {
        dfs1(v);
        if(len[v]>len[son[u]]) son[u]=v;
    }
    len[u]=len[son[u]]+1;
}
void dfs2(int u,int l)
{
    if(!son[u]) lp.push_back(l);
    else
    {
        dfs2(son[u],l+1);

        for(int v:g[u])
            if(v!=son[u])
                dfs2(v,1);
    }
}
void solve()
{
    lp.clear();
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        g[i].clear();
        son[i]=0,len[i]=0;
    }
    for(int i=2;i<=n;i++)
    {
        int u;
        cin>>u;
        g[u].push_back(i);
    }
    dfs1(1);
    dfs2(1,1);

    sort(lp.begin(),lp.end(),greater<int>());
    int ans=lp.size();
    for(int i=0;i<lp.size();i++)
        ans=min(ans,i+lp[i]);
    cout<<ans<<'\n';
}
signed main()
{
    //ios;
    int _t=1;
    cin>>_t;
    while(_t--) solve();
    system("pause");
    return 0;
}

E

Find Maximum

题意:

 思路:打表发现与f(x)的值与x的三进制有关,若三进制下每有一个2,答案加3;每有一个1,答案加2;每有一个0,答案加1.我们让x从下界l开始改变,枚举从哪一位开始改变。只有当R的某一位大于L的对应位时才可以开始改变。当可以改变时,若当前从第i位开始改变,若R该位上是2,那么我们可以让x该位为1,后面全为2;若R该位上是1,那么我们让x该位为0,后面全2.(注意x不能有前置0)

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define PII pair<int,int>
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;

using namespace std;
ll l,r;
int ql[N],qr[N];
int cntl,cntr;
void solve()
{
    cntl=cntr=0;
    cin>>l>>r;
    while(l)
    {
        ql[++cntl]=l%3;
        l/=3;
    }
    while(r)
    {
        qr[++cntr]=r%3;
        r/=3;
    }
    ll ret=0,ans=0;
    bool f=0;
    for(int i=cntr;i>=1;i--)
    {
        if(qr[i]>ql[i]) f=1;
        if(f)
        {
            if(qr[i]==2)
            {
                ret=max(ret,ans+2+(i-1)*3);
            }
            else if(qr[i]==1)
            {
                if(i==cntr) ret=max(ret,ans+(i-1)*3);
                else ret=max(ret,ans+1+(i-1)*3);
            }
        }
        if(qr[i]==2) ans+=3;
        else if(qr[i]==1) ans+=2;
        else ans+=1;
    }
    cout<<max(ans,ret)<<'\n';
    while(cntl) ql[cntl--]=0;
}
signed main()
{
    //ios;
    int _t=1;
    cin>>_t;
    while(_t--) solve();
    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_62615329/article/details/130045638