2020年绵阳CCPC部分题解

比赛链接:https://qoj.ac/contest/1838

D.拆除炸弹

恐怖分子在一栋建筑里放置了一些炸弹!我们的英雄,小马,决定去救建筑里的人。不幸的是,炸弹不止一个,小马无法拆除所有的炸弹。为了争取更多时间让别人逃生,小马决定牺牲自己。

建筑里有 \(n\) 个炸弹,每个炸弹都有一个倒计时钟。一开始,第 $ i $ 个炸弹的时钟设置为$ a_i $。然后:

  1. 小马选择一个炸弹,使其时钟增加 1。
  2. 每个炸弹的时钟减少 1。
  3. 如果至少有一个时钟变为负数,所有炸弹都会爆炸。否则,返回步骤 1。

显然,爆炸是不可避免的。多么悲伤的故事。但小马现在不在乎自己的生存。他只想争取更多时间。那么,你能告诉他在爆炸前最多可以执行步骤 1 多少次吗?
\(Input\)

输入的第一行包含一个整数 \(T\)\(1 \leq T \leq 100\))——测试用例的数量。

输入的第二行包含一个整数 \(n\)\(2 \leq n \leq 10^5\))——炸弹的数量。\(n\) 的总和不会超过 \(3 \times 10^5\)

下一行包含 \(n\) 个数字 \(a_1, a_2, \ldots, a_n\)\(0 \leq a_1, a_2, \ldots, a_n \leq 10^9\))——炸弹的初始时钟。
\(Output\)
对于第 \(x\) 个测试用例,如果答案是 \(y\),请在一行中输出 \(Case \#x: y\)
\(Sample\)
2
2
1 1
3
1 2 3


Case #1: 3
Case #2: 4

思路:直接二分存在全都保留的时间,然后得出后再加上一就是答案了,经典二分问题

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
// inline ll read()
// {
//     ll x=0,f=1;
//     char ch=getchar();
//     while(ch<'0'||ch>'9')
//     {
//         if(ch=='-')
//             f=-1;
//         ch=getchar();
//     }
//     while(ch>='0' && ch<='9')
//         x=x*10+ch-'0',ch=getchar();
//     return x*f;
// }
ll a[250000];
int main()
{
    fio();
    ll t; ll gs=0;
    cin>>t;
    while(t--)
    {
        ll n;
        cin>>n;
       
        gs++;
        for(ll i=1;i<=n;i++)cin>>a[i];
        ll l=0,r=(ll)1e18;
        while(l<=r)
        {
            ll mid=(l+r)>>1;
            ll cnt=mid;
            priority_queue<ll>q;
            ll pd=0;
            for(ll i=1;i<=n;i++)
            {
                if(a[i]-mid>=0)continue;
                else 
                {
                    if(cnt+a[i]-mid>=0)
                    {
                        cnt+=(a[i]-mid);
                    }
                    else 
                    {
                        pd=1;
                    }
                }
            }
            if(pd)
            r=mid-1;
            else 
            l=mid+1;
        }
        cout<<"Case"<<" #"<<gs<<":"<<" "<<r+1<<endl;
    }
}

G.纸牌游戏

小兔子和小马喜欢玩奇怪的纸牌游戏。现在,他们正在玩一种叫做“0123游戏”的纸牌游戏。
桌子上有几张牌。其中 \(c_0\) 张牌标有数字0,\(c_1\) 张牌标有数字1,\(c_2\) 张牌标有数字2,\(c_3\) 张牌标有数字3。小兔子和小马轮流玩游戏,小兔子先开始。在每一轮中,玩家应该选择两张牌,使得这两张牌上的数字之和不超过3,然后用一张标有它们和的牌替换这两张牌。无法进行移动的玩家输掉游戏。
小兔子和小马想知道谁会赢得游戏。
\(Input\)
输入的第一行包含一个整数 \(T\)\(1 \leq T \leq 10^5\))——测试用例的数量。
每个测试用例包含四个整数 \(c_0, c_1, c_2, c_3\)\(0 \leq c_0, c_1, c_2, c_3 \leq 10^9\))——分别标有 \(0, 1, 2, 3\) 的牌的数量。
\(Output\)
对于第x个测试用例,如果小兔子赢了,输出一行“Case #x: Rabbit”。否则,输出一行“Case #x: Horse”。
\(Sample\)
2
1 1 1 1
2 2 2 2


Case #1: Horse
Case #2: Rabbit

思路:这题就是打表找规律,打表出来后要分情况讨论,具体也是按着表的规律打出答案的,与模3有关,做这道题做麻了


#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                            long long 
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 1e9+7;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int main()
{
    ll t;
    cin>>t;
    ll gs=0;
    while(t--)
    {
        gs++;
    cout<<"Case #"<<gs<<": ";
    ll a,b,c,d;
    cin>>a>>b>>c>>d;
    ll ans;
    if(b==0)
    {
        if(a)
        {
            if(c||d)
            ans=a%2;
            else 
            {
                if(a>=2&&a%2==0)ans=1;
                else ans=0;
            }
        }
        else ans=0;
    }
    else if(c==0)
    {
       if(a==0)
       {
       if(b%3==2)ans=1;
       else ans=0;
       }
       else if(a%2==1)
       {
        if(b==1)ans=1;
        else if(b==2)ans=0;
        else if(b%3==2)ans=0;
        else ans=1;
       }
       else 
       {
        if(b==1)ans=0;
        else if(b==2)ans=1;
        else if(b%3==2)ans=1;
        else ans=0;
       }
    }
    else 
    {
        if(b%3==1)
        {
        ans=1;
        if(a%2)ans^=1;
        }
        else if(b%3==2)
        {
            if(a%2==0)ans=1;
            else 
            {
                if(c==1)ans=0;
                else ans=1;
            }
        }
        else if(b%3==0)
        {
            if(a%2==0)
            ans=0;
            else ans=1;
        }
    }
    cout<<(ans==0?"Horse":"Rabbit")<<endl;
    }
}

附赠打表代码:


#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                            long long 
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 1e9 + 7;
ll ksm(ll x, ll y)
{
    ll ans = 1;
    while (y)
    {
        if (y & 1)
        {
            ans = ans % mod * (x % mod) % mod;
        }
        x = x % mod * (x % mod) % mod;
        y >>= 1;
    }
    return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
    if (y == 0)
        return x;
    else
        return gcd(y, x % y);
}
void fio()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
}
ll dfs(ll a, ll b, ll c, ll d, ll sd)//1为r输,0为b输了
{
    ll pd1 = 0, pd2 = 0;
    if (a == 0)
    {
        if (b == 0)
            return sd % 2;
        else if (b == 1)
        {
            if (c > 0)
            {
                ll j = dfs(a, b - 1, c - 1, d + 1, sd + 1);
                if (j == 1)pd1 = 1;
                else pd2 = 1;
            }
            else return sd % 2;
        }
        else
        {
            if (c > 0)
            {
                ll j = dfs(a, b - 1, c - 1, d + 1, sd + 1);
                if (j == 1)pd1 = 1;
                else pd2 = 1;
            }
            ll j = dfs(a, b - 2, c + 1, d, sd + 1);
            if (j == 1)pd1 = 1;
            else pd2 = 1;
        }
    }
    else
    {
        if (b > 0 || c > 0 || d > 0)
        {
            ll j = dfs(a - 1, b, c, d, sd + 1);
            if (j == 1)pd1 = 1;
            else pd2 = 1;
            if (b == 1)
            {
                if (c > 0)
                {
                    ll j = dfs(a, b - 1, c - 1, d + 1, sd + 1);
                    if (j == 1)pd1 = 1;
                    else pd2 = 1;
                }
            }
            else if (b >= 2)
            {
                if (c > 0)
                {
                    ll j = dfs(a, b - 1, c - 1, d + 1, sd + 1);
                    if (j == 1)pd1 = 1;
                    else pd2 = 1;
                }
                ll j = dfs(a, b - 2, c + 1, d, sd + 1);
                if (j == 1)pd1 = 1;
                else pd2 = 1;
            }
        }
        else if (a >= 2)
        {
            ll j = dfs(a - 1, b, c, d, sd + 1);
            if (j == 1)pd1 = 1;
            else pd2 = 1;
        }
        else return sd % 2;
    }
    if (sd % 2 == 0)//h想赢
    {
        if (pd1)return 1;
        else return 0;
    }
    else
    {
        if (pd2)return 0;
        else return 1;
    }
}
int main()
{
    fio();
    ll a, b, c, d;
    for (ll i = 2; i <= 2; i++)
    {
        for (ll j = 0; j <= 0; j++)
        {
            for (ll k = 1; k <= 10; k++)
            {
                for (ll d = 0; d <= 0; d++)
                {
                    ll op = dfs(i, j, k, d, 1);
                    //cout<<i<<" "<<j<<" "<<k<<" "<<d<<" "<<endl;
                    cout << (op == 0 ? "Rabbit" : "Hourse") << endl;
                }
            }
        }
    }
}

J.手工艺的乐趣

小马总是做一些手工艺品,这让他充满了快乐。这次,他建造了一个可以周期性地打开和关闭灯泡的电路。
当然,以下是题目的中文翻译,并且使用了Markdown符号化
电路中有 \(n\) 个灯泡,第 \(i\) 个灯泡有一个周期 \(t_i\) 和一个亮度 \(x_i\)。正式地说,第 \(i\) 个灯泡将在第 \((2kt_i + 1)\) 秒到第 \((2kt_i + t_i)\) 秒之间打开,并且在第 \((2kt_i + t_i + 1)\) 秒到第 \((2kt_i + 2t_i)\) 秒之间关闭,其中 \(k = 0, 1, 2, \ldots\)。当第 \(i\) 个灯泡打开时,它的亮度将是 \(x_i\),否则它的亮度将是 0。
现在,小马想知道,从第一秒到第 \(m\) 秒,所有灯泡中的最大亮度是多少。
\(Input\)
第一行输入包含一个整数 \(T\) \((1 \leq T \leq 100)\) —— 测试用例的数量。
每个测试用例的第一行包含两个整数 \(n, m\) \((1 \leq n, m \leq 10^5)\) —— 灯泡的数量,以及你需要输出的整数数量。\(n\)\(m\) 的总和不会超过 \(2 \times 10^5\)
接下来的 \(n\) 行,第 \(i\) 行包含两个整数 \(t_i, x_i\) \((1 \leq t_i, x_i \leq 10^5)\) —— 第 \(i\) 个灯泡的周期和亮度。
\(Output\)
\(x\) 个测试用例以 \(Case \#x:\) 开始,后面跟着 \(m\) 个整数。第 \(i\) 个整数表示在第 \(i\) 秒时所有灯泡中的最大亮度。如果在第 \(i\) 秒没有灯泡亮着,则输出 0。
\(Sample\)
3
2 3
1 1
2 2
2 5
1 2
2 3
3 3
1 1
1 2
1 3


Case #1: 2 2 1
Case #2: 3 3 2 0 3
Case #3: 3 0 3

思路:首先对于相同的t,我们只要找对应的x最大就好了,然后存储各种t。然后根据t的周期性,枚举各个区间,时间复杂度是\({n/1}+{n/2}+...=nlogn\),然后直接用线段树去区间修改最大值就好了,总时间复杂度\(n*logn*logn\)


#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                               int
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
const ll maxn = 1e5+5;
struct s
{
	ll l, r;
	ll ad, v, cf;//ad为加法的懒惰标记,cf为乘法的懒惰标记
}p[maxn << 2];
ll fa[maxn << 2];
void build(ll i, ll l, ll r)
{
	p[i].l = l,p[i].r = r,p[i].v = 0;
	p[i].ad = 0,p[i].cf = 1;
	if (l == r)
	{
		fa[l] = i;
		return;
	}
	build(i << 1, l, (l + r) >> 1);
	build(i << 1 | 1, ((l + r) >> 1) + 1, r);
}
void push_down(ll i)
{
	if(p[i].ad)
    {
        p[i<<1].v=max(p[i<<1].v,p[i].ad);
        p[i<<1|1].v=max(p[i<<1|1].v,p[i].ad);
        p[i<<1].ad=max(p[i].ad,p[i<<1].ad);
        p[i<<1|1].ad=max(p[i].ad,p[i<<1|1].ad);
        p[i].ad=0;
    }
}
void udq(ll i, ll ad, ll cf, ll l, ll r)//区间修改
{
	if (p[i].l == l && p[i].r == r)
	{
		p[i].v=max(p[i].v,ad);
        p[i].ad=max(p[i].ad,ad);
		return;
	}
	push_down(i);
	ll i1 = i << 1, i2 = i << 1 | 1;
	if (l <= p[i1].r)
	{
		if (r <= p[i1].r)
			udq(i1, ad, cf, l, r);
		else
			udq(i1, ad, cf, l, p[i1].r);
	}
	if (r >= p[i2].l)
	{
		if (l >= p[i2].l)
		{
			udq(i2, ad, cf, l, r);
		}
		else
			udq(i2, ad, cf, p[i2].l, r);
	}
	p[i].v = max(p[i1].v,p[i2].v);
}
ll query(ll i, ll l, ll r)
{
	ll ans = 0;
	if (p[i].l == l && p[i].r == r)
	{
		ans = p[i].v;
		return ans;
	}
	push_down(i);
	ll i1 = i << 1, i2 = i << 1 | 1;
	if (l <= p[i1].r)
	{
		if (r <= p[i1].r)
			ans = max(ans , query(i1, l, r));
		else
			ans = max(ans , query(i1, l, p[i1].r));
	}
	if (r >= p[i2].l)
	{
		if (l >= p[i2].l)
		{
			ans = max(ans , query(i2, l, r));
		}
		else
			ans = max(ans , query(i2, p[i2].l, r));
	}
	return ans;
}
ll a[250000];
ll b[250000];
int main()
{
    fio();
   ll t;
   cin>>t;
   ll gs=0;
   while(t--)
   {
    gs++;
    ll n,m;
    cin>>n>>m;
    ll cnt=0;
    build(1,1,m);
    for(ll i=1;i<=n;i++)
    {
        ll x,y;
        cin>>x>>y;
        if(b[x]==0)
        {
            cnt++;
            a[cnt]=x;
        }
        b[x]=max(b[x],y);
    }
    for(ll i=1;i<=cnt;i++)
    {
        for(ll k=1;k<=m;k+=a[i]*2)
        {
            ll l=k,r=min(k+a[i]-1,m);
            udq(1,b[a[i]],0,l,r);
        }
    }
    for(ll i=1;i<=cnt;i++)
    {
        b[a[i]]=0;
    }
    cout<<"Case #"<<gs<<":";
    for(ll i=1;i<=m;i++)
    {
        cout<<" ";
        cout<<query(1,i,i);
    }
    cout<<endl;
   }
}

K.知识就是力量

知识就是力量。小兔子和小马都渴望更多的知识,所以他们总是互相出一些谜题。今天,小兔子给小马出了一个新的谜题。

小兔子给小马一个正整数 \(x\)。小马需要找到一个整数集合 \(S = \{a_1, a_2, \ldots, a_n\}\),满足以下条件:

  • \(n \geq 2\)
  • \(a_i > 1\),对于 \(1 \leq i \leq n\)
  • \(\sum_{i=1}^{n} a_i = x\)
  • \(a_i\)\(a_j\) 是互质的,对于任何 \(i \neq j\)
    例如,如果 \(x = 12\),那么 \(S = \{3, 4, 5\}\)\(S = \{5, 7\}\) 以及 \(S = \{2, 3, 7\}\) 都是有效的集合。两个整数被称为互质,如果唯一正整数能同时整除它们的是1。
    我们定义 \(a_{max}\) 为集合 \(S\) 中的最大元素,\(a_{min}\) 为集合 \(S\) 中的最小元素。小兔子希望 \((a_{max} - a_{min})\) 的值尽可能小。你能帮助小马找到 \((a_{max} - a_{min})\) 的最小值吗?
    \(Input\)
    输入的第一行包含一个整数 \(T\) \((1 \leq T \leq 10^5)\) —— 测试用例的数量。
    每个测试用例包含一个整数 \(x\) \((5 \leq x \leq 10^9)\) —— 小兔子给小马的整数。
    \(Output\)
    对于第 \(x\) 个测试用例,如果答案是 \(y\),请在一行中输出 Case #x: y。如果没有可能的解,请在一行中输出 Case #x: -1
    \(Sample\)
    4
    5
    6
    7
    10

Case #1: 1
Case #2: -1
Case #3: 1
Case #4: 3

思路:首先特判6错误,然后思考,对于一个奇数来讲,他的最小值应该始终为1,因为一个大于等于5的奇数总能拆成两个相邻的数

1.对于一个偶数来讲,如果它除以二,得出的是一个偶数,则值应该为2,这个显然是对的

2.如果非偶数呢,它的值的最大值应该为4,最小值应该大于2,如14,可为5 9

现在对于3进行特判,可以设第拆分出的第一个为数为x(从小到大)

如果x为奇数,显然答案为x,x+2,x+3为拆分答案,所以有等式\(3*x+5=n\)

如果x为偶数,显然答案为x,x+1,x+3为拆分答案,所以有等式\(3*x+4=n\)

最后进行判定是否存在上述等式成立,如果存在则答案为3否则为4

#include <iostream>
#include <numeric>
#define endl '\n'
#define ll long long
using namespace std; 
const ll mod=998244353;
ll qpow(ll x,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1)
            ans=ans*x%mod;
        x=x*x%mod;
        b>>=1;
    }
    return ans;
}
ll inv(ll x)
{
    return qpow(x,mod-2);
}
ll t,x;
ll gcd(ll x,ll y)
{
    return y==0?x:gcd(y,x%y);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>t;
    for(int i=1;i<=t;i++)
    {
        cout<<"Case #"<<i<<": ";
        cin>>x;
        if(x&1)
        {
            cout<<1<<endl;
        }
        else if((x/2)&1)
        {
            if(x/2/2>1)
            {
                ll ans=4;
                if(x-3>0&&(x-3)%3==0)
                {
                    ll a=(x-3)/3,b=(x-3)/3+1,c=(x-3)/3+2;
                    if(gcd(a,b)==1&&gcd(a,c)==1&&gcd(b,c)==1)
                        ans=min(ans,(ll)2);
                }
                if(x-4>0&&(x-4)%3==0)
                {
                    ll a=(x-4)/3,b=(x-4)/3+1,c=(x-4)/3+3;
                    if(gcd(a,b)==1&&gcd(a,c)==1&&gcd(b,c)==1)
                        ans=min(ans,(ll)3);
                }
                if(x-5>0&&(x-5)%3==0)
                {
                    ll a=(x-5)/3,b=(x-5)/3+2,c=(x-5)/3+3;
                    if(gcd(a,b)==1&&gcd(a,c)==1&&gcd(b,c)==1)
                        ans=min(ans,(ll)3);
                }
                cout<<ans<<endl;
            }
            else
                cout<<-1<<endl;
        }
        else
        {
            cout<<2<<endl;
        }
    }
}
posted @ 2024-11-13 22:27  长皆  阅读(2)  评论(0编辑  收藏  举报