2025“钉耙编程”中国大学生算法设计暑期联赛(6)
cat学乘法
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
int a[200010];
/*
10
5
-1 -2 -3 0 1
*/
signed main( )
{
std::ios::sync_with_stdio(false);
int T;cin>>T;
while(T--){
cin>>n;
int cnt_0=0ll;int cnt0=0ll;int mn=1e10;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]==0ll)cnt_0++;
else if(a[i]<0ll){cnt0++;mn=min(mn,-a[i]);}
else if(a[i]>0){mn=min(mn,a[i]);}
}
if(cnt_0!=0ll){
cout<<cnt_0<<'\n';
}else {
if(cnt0&1){
cout<<mn+1<<'\n';
}else cout<<0<<'\n';
}
}
}
对撞器
a[1]或a[n],2~n-1都可以贡献a[1]
中间,2~pos-1 pos+1~n-1可以贡献a[pos]
学习多个最大值处理,相等的都加到vec,头和尾可能是1,n
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=200010;
int n;
int a[N];
signed main(){
int T;cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
if(n<=2){
cout<<0<<'\n';continue;
}
int mx=a[1];for(int i=1;i<=n;i++)mx=max(mx,a[i]);
vector<int> vec;for(int i=1;i<=n;i++){if(a[i]==mx)vec.push_back(i);}
if(*vec.begin()==1||vec.back()==n){
cout<<(n-2)*mx<<'\n';
}else {
cout<<(n-3)*mx+max(a[1],a[n])<<'\n';
}
}
}
传送排序
留下来没有用过传送的数构成一个上升子序列
f[i]表示以p[i]为结尾的留下的子序列 需要的操作数量
考虑这个子序列上一个元素p[j],如果p[j]=p[i]-1那就正是下一个元素无需操作,f[i]=f[j]
如果p[j]<p[i]-1那就需要现在把本来在之间的p[i]-p[j]-1个元素插进去,f[i]=f[j]+p[i]-p[j]-1+1
由于开头和结尾均可插入,添加0和n+1也作为元素
第二种操作用树状数组维护1<=j<=i-1 f[j]-p[j]最小值,由于j=0 f[j]-j=f[0]-0=0用树状数组差不到,需要额外拿出来
#include<iostream>
using namespace std;
#define INF 0x3f3f3f3f
const int N=200010;
int n;
int tr[N];
int p[N];
int b[N];
int f[N];
int lowbit(int x){
return x&(-x);
}
void add(int x,int k){
int cnt=0;
for(int i=x;i<=n+1;i+=lowbit(i)){
tr[i]=min(tr[i],k);
}
}
int query(int x){
int res=INF;
for(int i=x;i>0;i-=lowbit(i))res=min(res,tr[i]);
return res;
}
int main(){
int T;cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++){cin>>p[i];b[p[i]]=i;tr[i]=INF;f[i]=INF;}
p[0]=0;p[n+1]=n+1;b[0]=0;b[n+1]=n+1;tr[0]=0;tr[n+1]=INF;f[0]=0;f[n+1]=INF;
for(int i=0;i<=n+1;i++){
if(i==0){
f[i]=0;
continue;
}
f[i]=min(f[i],f[b[p[i]-1]]);
if(p[i]>2){int t=query(p[i]-2);f[i]=min(f[i],t+p[i]);}
f[i]=min(f[i],0+p[i]);
add(p[i],f[i]-p[i]);
}
/* for(int i=0;i<=n+1;i++){
cout<<f[i]<<" ";
}cout<<endl; */
cout<<f[n+1]<<'\n';
}
}
cats 的 max
状压dp第二类
第一排O((1<<m)nm)
转移部分 每一列分别在sta,sta0,stasta0里,有3m种 O(3^mkk)
#include<iostream>
using namespace std;
#define int long long
int n,m,k;
int f[(1<<13)+10][20];//已经产生最大值的列集合 已经选的行个数
int a[1010][20];
signed main(){
std::ios::sync_with_stdio(false);
int T;cin>>T;
while(T--){
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
for(int j=0;j<m;j++){
cin>>a[i][j];
}
}
if(k>=m){
int ans=0;
for(int j=0;j<m;j++){
int mx=0;
for(int i=1;i<=n;i++){
mx=max(mx,a[i][j]);
}
ans+=mx;
}
cout<<ans<<'\n';continue;
}
for(int sta=1;sta<(1<<m);sta++)for(int k1=0;k1<=k;k1++)f[sta][k1]=0;
for(int sta=1;sta<(1<<m);sta++){
for(int i=1;i<=n;i++){
int tem=0;
for(int col=0;col<m;col++){
if(sta&(1<<col)){
tem+=a[i][col];
}
}
f[sta][1]=max(f[sta][1],tem);
}
}
//用子集和它的补集
//子集必然全算完了
int ans=0;
for(int sta=1;sta<(1<<m);sta++){
for(int k1=1;k1<=k;k1++){
for(int sta0=sta;sta0;sta0=(sta0-1)&sta){
for(int k0=0;k0<=k1;k0++){
// if(sta==15&&k1==2&&sta0==11&&k0==1){
// cout<<"get"<<f[sta][k1]<<" "<<f[sta0][k0]<<" "<<f[sta^sta0][k1-k0]<<'\n';
// }
f[sta][k1]=max(f[sta][k1],f[sta0][k0]+f[sta^sta0][k1-k0]);
ans=max(ans,f[sta][k1]);
}
}
}
}
cout<<ans<<'\n';
}
}
取模
随机化
#include<bits/stdc++.h>
#include <random>
#include <chrono>
using namespace std;
const int N=500010;
int n,m,c;
int a[N];
int b[N];
std::mt19937 rd(std::chrono::system_clock::now().time_since_epoch().count());
bool check(int k){
for(int i=1;i<=min(5,n);i++){
int tmp=0;
for(int j=a[i]%k;j<=m;j+=k){//a[i]所在剩余类
tmp+=b[j];
}
if(tmp!=n/c&&tmp!=0)return 0;
}
for(int i=0;i<k;i++){
int tmp=0;
for(int j=i;j<=m;j+=k){
tmp+=b[j];
}
if(tmp!=n/c&&tmp!=0)return 0;
}
return 1;
}
signed main(){
std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--){
cin>>n>>m>>c;
for(int i=0;i<=m;i++)b[i]=0;
for(int i=1;i<=n;i++){cin>>a[i];b[a[i]]++;}
// shuffle(a + 1, a + 1 + n, rd);
if(check(m+1)){
cout<<-1<<'\n';continue;
}
vector<int> ans;
for(int i=1;i<=m;i++){
if(check(i))ans.push_back(i);
}
cout<<ans.size()<<' ';
for(auto x:ans){
cout<<x<<' ';
}cout<<'\n';
}
}

浙公网安备 33010602011771号