目录
赛时解决题目:B,E,H,L
E:
题意:给两行n个骑士,第一行第i个与第二行第i个面对面,每个骑士都有血条h[i]。由第一行先开始,选择一个存活骑士的下标,扣对应的对面一个骑士一滴血,接下来轮到第二行,轮流。双方都已己方骑士剩余数量最大化为目标,问第一行最后剩下多少骑士。
解题思路:很明显,如果a[i]>b[i],那么a[i]肯定能战胜b[i],如果a[i]==b[i],那么谁先手谁能存活。
#include<bits/stdc++.h>
#define endl '\n'
#define ll int
#define int long long
#define double long double
#define Int __int128
#define pb push_back
#define N (int)3e5+10
#define MAX_LOG 21
#define ff first
#define ss second
#define M 5005
#define ull unsigned long long
using namespace std;
const double PI=3.1415926535897932385;
const ll LLMAX=9223372036854775807ll;
const ll LLMIN=-9223372036854775808ll;
//const int MAX_INT=0x3f3f3f3f;
const int IIMAX=2147483647;
const int IIMIN=-2147483648;
const int INF=0x3f3f3f3f;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b)
{
if(b) while((a%=b)&&(b%=a));
return a+b;
}//最大公约数函数
ll spid(ll a,ll b,ll p)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%p;
b>>=1;
a=a*a%p;
}
return ans;
}//快速幂函数
///泡沫在阳光下闪烁,像星辰在寂静得夜空中闪耀
///秋雨
ll a[N];
ll b[N];
void solve()
{
ll n;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
bool ret=1;
ll ans=0;
for(int i=1;i<=n;i++)
{
if(a[i]>b[i])ans++;
else if(a[i]==b[i])
{
ans+=ret;
ret^=1;
}
}
cout<<ans<<'\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t=1;
cin>>t;
while(t--)
{
solve();
}
}
///在秋天邂逅, 在春天发芽,在夏天壮大,在秋天萧瑟,在冬天萎缩,
///而后,春天再度归来。
L:
题意:给你长度为n的数组,a[i]>0&&a[i]<=100,你可以进行任意次操作,选择一个下标i(0<i<n),让a[i+1]--,a[i]++。问这个数组的最大乘积是多少。
解题思路:我们肯定希望每个数字尽可能相等,发现数据很小,尽可能取均值即可。
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define int long long
#define double long double
#define Int __int128
#define pb push_back
#define N (int)3e5+10
#define MAX_LOG 21
#define ff first
#define ss second
#define M 5005
#define ull unsigned long long
using namespace std;
const double PI=3.1415926535897932385;
const ll LLMAX=9223372036854775807ll;
const ll LLMIN=-9223372036854775808ll;
//const int MAX_INT=0x3f3f3f3f;
const int IIMAX=2147483647;
const int IIMIN=-2147483648;
const int INF=0x3f3f3f3f;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b)
{
if(b) while((a%=b)&&(b%=a));
return a+b;
}//最大公约数函数
ll spid(ll a,ll b,ll p)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%p;
b>>=1;
a=a*a%p;
}
return ans;
}//快速幂函数
///泡沫在阳光下闪烁,像星辰在寂静得夜空中闪耀
///秋雨
ll a[N];
ll p=998244353;
void solve()
{
ll n;
cin>>n;
for(int i=1; i<=n; i++)cin>>a[i];
while(1)
{
ll ret=1;
for(int i=n;i>1;i--)
{
if(a[i]>a[i-1])
{
ret=0;
ll sum=a[i]+a[i-1];
a[i]=sum>>1;
a[i-1]=sum-a[i];
}
}
if(ret) break;
}
ll ans=1;
for(int i=1;i<=n;i++)
{
ans*=a[i];
ans%=p;
}
cout<<ans<<'\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t=1;
cin>>t;
while(t--)
{
solve();
}
}
///在秋天邂逅, 在春天发芽,在夏天壮大,在秋天萧瑟,在冬天萎缩,
///而后,春天再度归来。
B:
题意:你有无数块长为2,宽为1的多米诺骨牌,给你一个n*m的矩阵,问你能不能用这种多米诺骨牌拼成这个矩阵。
可能有两个限制:
限制1:短边不能和短边完整共用一条边
限制2:长边不能和长边完整共用一条边
解题思路:针对各种情况特判即可。
#include<bits/stdc++.h>
#define endl '\n'
#define ll int
#define int long long
#define double long double
#define Int __int128
#define pb push_back
#define N (int)3e5+10
#define MAX_LOG 21
#define ff first
#define ss second
#define M 5005
#define ull unsigned long long
using namespace std;
const double PI=3.1415926535897932385;
const ll LLMAX=9223372036854775807ll;
const ll LLMIN=-9223372036854775808ll;
//const int MAX_INT=0x3f3f3f3f;
const int IIMAX=2147483647;
const int IIMIN=-2147483648;
const int INF=0x3f3f3f3f;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b)
{
if(b) while((a%=b)&&(b%=a));
return a+b;
}//最大公约数函数
ll spid(ll a,ll b,ll p)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%p;
b>>=1;
a=a*a%p;
}
return ans;
}//快速幂函数
///泡沫在阳光下闪烁,像星辰在寂静得夜空中闪耀
///秋雨
void solve()
{
ll n,m,a,b;
cin>>n>>m>>a>>b;
if(n>m)swap(n,m);
if(n==1&&m==2)
{
cout<<"Yes\n";
return;
}
if(n*m%2)
{
cout<<"No\n";
return;
}
if(a==1&&b==1)
{
cout<<"Yes\n";
return;
}
else if(a==0&&b==1)///规则1存在
{
if(n==1)
{
cout<<"No\n";
return;
}
cout<<"Yes\n";
return;
}
else if(a==1&&b==0)///规则2存在
{
if(n==1&&m%2==0)
{
cout<<"Yes\n";
return;
}
cout<<"No\n";
return;
}
else///都存在
{
if(n==1&&m==2)
{
cout<<"Yes\n";
return;
}else
{
cout<<"No\n";
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t=1;
cin>>t;
while(t--)
{
solve();
}
}
///在秋天邂逅, 在春天发芽,在夏天壮大,在秋天萧瑟,在冬天萎缩,
///而后,春天再度归来。
H:
题意:给一个无相图(可能有环),给m条边,点上有权值,权值由你自由分配。问从你任意选的一个点开始,每次走这个点与之相连的比这个点权值还小的权值最小的相邻点,问最多能走多少个点。
解题思路:发现数据范围n是2e5,对于每次取点,就会增加这个点相邻点数量的时间复杂度,所以粗略计算,时间复杂度是40*40*a1*a2*...*ay,这里a1+a2+a3+...+ay=40,大概能过,写一发dfs,就暴力过去了。需要注意的是,每次取点取的是相邻点中,权值最小的点,也就是说,当我们取了其中一个相邻点,那么其他相邻点在之后的过程中就不能取了。也就是说vis数组不能是bool,而应该是记录被打上多少次标记。具体见代码。
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define int long long
#define double long double
#define Int __int128
#define pb push_back
#define N (int)3e5+10
#define MAX_LOG 21
#define ff first
#define ss second
#define M 5005
#define ull unsigned long long
using namespace std;
const double PI=3.1415926535897932385;
const ll LLMAX=9223372036854775807ll;
const ll LLMIN=-9223372036854775808ll;
//const int MAX_INT=0x3f3f3f3f;
const int IIMAX=2147483647;
const int IIMIN=-2147483648;
const int INF=0x3f3f3f3f;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b)
{
if(b) while((a%=b)&&(b%=a));
return a+b;
}//最大公约数函数
ll spid(ll a,ll b,ll p)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%p;
b>>=1;
a=a*a%p;
}
return ans;
}//快速幂函数
///泡沫在阳光下闪烁,像星辰在寂静得夜空中闪耀
///秋雨
unordered_set<ll>st[41];
vector<int>vis(40,0);
ll ans=0;
void dfs(int u,int fa,int cnt)
{
ans=max(cnt,ans);
for(auto i:st[u])
{
if(vis[i]||fa==i)continue;
for(auto j:st[u])
vis[j]++;
dfs(i,u,cnt+1);
for(auto j:st[u])
vis[j]--;
}
};
void solve()
{
ll n,m;
cin>>n>>m;
for(int i=1; i<=m; i++)
{
ll u,v;
cin>>u>>v;
st[u].insert(v);
st[v].insert(u);
}
for(int i=1; i<=n; i++)
{
vis[i]=1;
dfs(i,-1,1);
vis[i]=0;
}
cout<<ans<<'\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t=1;
// cin>>t;
while(t--)
{
solve();
}
}
///在秋天邂逅, 在春天发芽,在夏天壮大,在秋天萧瑟,在冬天萎缩,
///而后,春天再度归来。