E 安
https://ac.nowcoder.com/acm/contest/81600/E
分析
简单博弈 / 思维题。
当 ai > bi
时,当前骑士一定存活。
当 ai < bi
时,当前骑士一定死亡。
为了使得自己存活的骑士尽可能多,若存在 ai = bi
的情况,一定会选择令该骑士去攻击对方,并且双方均会轮流优先选择此类骑士。
因此,记 ai > bi
的个数为aa,ai = bi
的个数为bb,则最终存活的棋子即为
a a + ⌈ b b 2 ⌉ aa + \lceil\frac{bb} {2} \rceil aa+⌈2bb⌉
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long long ll;
const ll mod = 998244353;
const int N = 1e5 + 7;
int n;
int a[N],b[N];
void solve(){
cin >> n;
for(int i = 1;i <= n;i++) cin >> a[i];
for(int i = 1;i <= n;i++) cin >> b[i];
int aa = 0,bb = 0;
for(int i = 1;i <= n;i++){
if(a[i] > b[i]) aa++;
else if(a[i] == b[i]) bb++;
}
cout << aa + (bb + 1) / 2 << '\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
B 珑
https://ac.nowcoder.com/acm/contest/81600/B
分析
多米诺骨牌经典问题。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long long ll;
const ll mod = 998244353;
const int N = 1e5 + 7;
int n,m,a,b;
void solve(){
cin >> n >> m >> a >> b;
if((n == 1 && m == 2) || (n == 2 && m == 1)){
cout << "Yes\n";
return ;
}
if((n & 1) && (m & 1)) cout << "No\n";
else if(b == 1){
if(a == 1) cout << "Yes\n";
else if(n == 1 || m == 1) cout << "No\n";
else cout << "Yes\n";
}
else if(a == 1){
if(n == 1 && m % 2 == 0) cout << "Yes\n";
else if(m == 1 && n % 2 == 0) cout << "Yes\n";
else cout << "No\n";
}else{
if(n == 1 && m == 2) cout << "Yes\n";
else if(n == 2 && m == 1) cout << "Yes\n";
else cout << "No\n";
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
L 知
https://ac.nowcoder.com/acm/contest/81600/L
分析
最终答案即为求 a1 * a2 * a3 * … * an 的最大值。
平均分配原则。
若 ai < ai+1
,则给 ai 增加 1,给 ai+1 减少 1,则答案一定不会变劣。
维护前缀和数组c,对于每个ai,计算出[i,i],[i,i+1],[i,i+2]…[i,n]的平均数的最大值s,
若ai < s,则将ai变为s即可。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long long ll;
const ll mod = 998244353;
const int N = 1e7 + 7;
ll a[N];
ll c[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--)
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
c[n + 1] = 0;
for (int i = 1; i <= n; i++)
{
c[i] = c[i - 1] + a[i];
}
for (int i = 1; i < n; i++)
{
ll s = 0;
for (int j = i + 1; j <= n; j++)
{
s = max(s, (a[i] + c[j] - c[i]) / (j - i + 1));
}
if (a[i] < s)
{
s-=a[i];
a[i] += s;
a[i + 1] -= s;
}
}
ll res = 1;
for (int i = 1; i <= n; i++)
{
res *= a[i];
res %= mod;
// cout << a[i] << ' ';
}
cout << res << '\n';
}
return 0;
}
H 入
https://ac.nowcoder.com/acm/contest/81600/H
分析
考虑若每个点只连了一条边,那么最终的方案数只有1个,即走完这条链。
若每个点连了两条边或者更多,每个点连的所有边只有一条会起作用,因此实际起作用的点不用超过n/2,所以直接爆搜,状态数也不会超过2^20约1e6。
注意爆搜时进行记忆化,可以结合状压dp来写,总时间复杂度约 O ( n ∗ 2 n ) O(n * 2^n) O(n∗2n)
代码
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 42;
struct stu1{
int y,nex;
}e[N*N];
int n,m,lin[N],cnt,ans;
void work(int x,int y){
e[++cnt]=(stu1){y,lin[x]}; lin[x]=cnt;
}
unordered_map<LL,int> mp[N];
void Get(int dq){
for(int i=0;i<n;i++) cout<<((dq>>i)&1);
cout<<endl;
}
int dfs(LL dq1,int x){
if(mp[x][dq1]) return max(mp[x][dq1],0);
LL dq2=dq1;
for(int i=lin[x];i;i=e[i].nex){
int y=e[i].y;
if(((dq1>>y-1)&1)==0){
dq2|=(1ll<<y-1);
}
} //zouguoqu
for(int i=lin[x];i;i=e[i].nex){
int y=e[i].y;
if(((dq1>>y-1)&1)==0){
//if(x==6) cout<<y<<endl;
mp[x][dq1]=max(mp[x][dq1],dfs(dq2,y)+1);
}
} //zouguoqu
// Get(dq1); Get(dq2);
//cout<<mp[dq1]<<' '<<x<<' '<<dq1<<endl;
if(!mp[x][dq1]) mp[x][dq1]=-1;
return max(mp[x][dq1],0);
}
int main()
{
scanf("%d%d",&n,&m);
int x,y;
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
work(x,y);
work(y,x);
}
for(int i=1;i<=n;i++) ans=max(ans,dfs((1ll<<i-1),i)+1);
printf("%d",ans);
}
场上就写出来了这4道,持续补题中…