A
要么全一个一个买
要么奇数买一个,剩下一对一对买;偶数全一对一对买
// LUOGU_RID: 155914117
#include <bits/stdc++.h>
#define ll long long
using namespace std;
void paralysis(){
int a,b,n;
cin>>n>>a>>b;
if (n&1){
cout<<min(a*n,n/2*b+a)<<"\n";
}else{
cout<<min(a*n,n/2*b)<<"\n";
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
cin>>T;
while (T--){
paralysis();
}
return 0;
}
B
发现
a
1
,
1
a_{1,1}
a1,1是最小的,模拟推出矩阵即可
// LUOGU_RID: 155914611
#include <bits/stdc++.h>
#define ll long long
using namespace std;
void paralysis(){
int n,c,d;
cin>>n>>c>>d;
vector<int> a(n*n);
int minn=1e9;
for (int i=0;i<n*n;i++){
cin>>a[i];
minn=min(minn,a[i]);
}
vector<vector<int>> val(n+1,vector<int>(n+1));
val[1][1]=minn;
vector<int> b;
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if (i+1<=n){
val[i+1][j]=val[i][j]+c;
}
if (j+1<=n){
val[i][j+1]=val[i][j]+d;
}
b.push_back(val[i][j]);
}
}
sort(a.begin(),a.end());
sort(b.begin(),b.end());
for (int i=0;i<n*n;i++){
// cout<<a[i]<<" "<<b[i]<<"\n";
if (a[i]!=b[i]){
cout<<"No\n";
return;
}
}
cout<<"Yes\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
cin>>T;
while (T--){
paralysis();
}
return 0;
}
C
左右一次攻击,整体来看,求出左右总攻击数,然后两遍遍历一下
#include <bits/stdc++.h>
#define int long long
using namespace std;
void paralysis(){
int n;
int k;
cin>>n>>k;
vector<int> a(n+1);
int tol=0;
for (int i=1;i<=n;i++){
cin>>a[i];
tol+=a[i];
}
if (k>=tol){
cout<<n<<"\n";
return;
}
int l=0,sum=0;
while (sum+a[l+1]<=(k+1)/2){
sum+=a[++l];
}
int r=n+1;
sum=0;
while (sum+a[r-1]<=k/2){
sum+=a[--r];
}
cout<<l+(n-r+1)<<"\n";
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
cin>>T;
while (T--){
paralysis();
}
return 0;
}
D
双指针维护区间
// LUOGU_RID: 155964350
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
using namespace std;
int cnt[1000005];
void paralysis(){
int n,k,m;
cin>>n>>m>>k;
vector<int> a(n+1),b(m+1);
for (int i=1;i<=n;i++){
cin>>a[i];
}
for (int i=1;i<=m;i++){
cin>>b[i];
cnt[b[i]]++;
}
cnt[0]=-1e9;
int ans=0;
for (int i=1,sum=0;i<=n;i++){
if (cnt[a[i]]>0){
sum++;
}
cnt[a[i]]--;
if (i>=m){
cnt[a[i-m]]++;
if (cnt[a[i-m]]>0){
sum--;
}
if (sum>=k){
ans++;
}
}
}
for (int i=1;i<=n;i++){
cnt[a[i]]=0;
}
for (int i=1;i<=m;i++){
cnt[b[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--){
paralysis();
}
return 0;
}
E
序列上区间开关灯的经典模型,发现每个区间要么操作要么不操作
所以从左到右遍历,遇0则操作,最后判断是否全1
// LUOGU_RID: 155967298
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
using namespace std;
void paralysis(){
int n;
cin>>n;
vector<int> a(n+1);
for (int i=1;i<=n;i++){
char ch;
cin>>ch;
a[i]=ch-'0';
}
for (int k=n;k>=1;k--){
vector<int> b(n+2);
bool flag=1;
for (int i=1;i<=n;i++){
b[i]+=b[i-1];
if ((a[i]+b[i])%2==0){
if (i+k-1>n){
flag=0;
break;
}else{
b[i]++;
b[i+k]--;
}
}
}
if (flag){
cout<<k<<"\n";
return;
}
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
cin>>T;
while (T--){
paralysis();
}
return 0;
}
F
首先 1 2 3一组可以异或抵消,但是4是单独的,只有偶数才行
所以4产生
⌊
p
4
2
⌋
\lfloor {p_4 \over 2} \rfloor
⌊2p4⌋的贡献
对于1 2 3有两种减少方法,一种只通过自身偶数抵消 贡献显然与4一样
另一种是取
m
i
n
(
p
1
,
p
2
,
p
3
)
min(p_1,p_2,p_3)
min(p1,p2,p3) 先用
m
i
n
min
min 组 123抵消,剩下两个大的减去
m
i
n
min
min 次后考虑偶数抵消。最后123数量都为min,贡献同4
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
using namespace std;
void paralysis(){
int a,b,c,d;
cin>>a>>b>>c>>d;
int ans=0;
int x=min(a,min(b,c));
ans=max((a-x)/2+(b-x)/2+(c-x)/2+x/2*3+(x&1),a/2+b/2+c/2);
cout<<ans+d/2<<"\n";
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
cin>>T;
while (T--){
paralysis();
}
return 0;
}
G
枚举
a
1
,
1
a_{1,1}
a1,1的因数,然后跑可达性dp
// LUOGU_RID: 155977533
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pos(x,y) (x-1)*m+y
using namespace std;
void paralysis(){
int n,m;
cin>>n>>m;
vector<vector<int>> a(n+1,vector<int>(m+1));
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
cin>>a[i][j];
}
}
vector<vector<int>> f(n+1,vector<int>(m+1));
auto check=[&](int d)->bool{
f[1][1]=d;
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
if (a[i][j]%d) continue;
if (f[i-1][j]==d||f[i][j-1]==d){
f[i][j]=d;
}
}
}
return f[n][m]==d;
};
int ans=0;
for (int i=1;i*i<=a[1][1];i++){
if (a[1][1]%i) continue;
if (check(a[1][1]/i)){
ans=max(ans,a[1][1]/i);
}
if (check(i)){
ans=max(ans,i);
}
}
cout<<ans<<"\n";
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
cin>>T;
while (T--){
paralysis();
}
return 0;
}
H
一个炮塔选择的范围产生正贡献时才会被考虑,我们发现产生正贡献
r
<
=
12
r<=12
r<=12,预处理出每个炮塔每个范围时能产生的贡献
那么问题变成了一个经典问题,二维数组 n ∗ m n*m n∗m 选 n n n 个数,列数不同最大和
方法一:跑一个最大费用最大流
方法二: 因为列数是12,所以状压dp也可以做
状压dp:
// LUOGU_RID: 155995446
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
int fac[20];
void paralysis(){
int n,m,k;
cin>>n>>m>>k;
vector<pair<int,int>> b;
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
char ch;
cin>>ch;
if (ch=='#'){
b.push_back({i,j});
}
}
}
vector<int> x(k+1),y(k+1),p(k+1);
for (int i=1;i<=k;i++){
cin>>x[i]>>y[i]>>p[i];
}
vector<vector<int>> f(k+1,vector<int>(13));
for (int i=1;i<=k;i++){
for (int j=1;j<=12;j++){
int sum=0;
for (auto [xx,yy]:b){
if ((x[i]-xx)*(x[i]-xx)+(y[i]-yy)*(y[i]-yy)<=j*j){
sum++;
}
}
f[i][j]=max(0,sum*p[i]-fac[j]);
}
}
int ans=0;
vector<int> g(1<<13);
for (int i=1;i<=k;i++){
for (int mask=(1<<13)-1;mask>=0;mask--){
for (int j=1;j<=12;j++){
if ((1<<j)&mask) continue;
g[mask|(1<<j)]=max(g[mask|(1<<j)],g[mask]+f[i][j]);
ans=max(ans,g[mask|(1<<j)]);
}
}
}
cout<<ans<<"\n";
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
fac[0]=1;
for (int i=1;i<=15;i++){
fac[i]=fac[i-1]*3;
}
int T=1;
cin>>T;
while (T--){
paralysis();
}
return 0;
}