11.9 正睿做题笔记
T1
这个题的一个想法是我们首先把所有点放入堆里,然后每次从堆中取出权值和最小的团,然后往这个团里每次插入一个可以插的点。但是这样放入堆里的元素个数无法估计,会被卡空间,下面有几种优化:
- 首先我们把堆换成 multiset,然后如果取出的元素个数加上集合内元素个数之和大于 \(k\),我们就可以把那些最大的删掉。另一个优化是如果当前元素大于 \(k\) 并且当前插入值比最大值大,我们就不插入。
- 我们首先把所有点的权值排序,然后我们每次取出一个团,有两种操作,第一种是去掉最大的那个点,换一个更大的点。或者我们直接往这个团里加一个能加的点中最小的点。
- 我们换一种思路,考虑二分这个值,然后考虑是否能找到 \(k\) 个团,使得这些团的权值都小于二分的值,我们考虑从空集开始扩展,每次加上一个能加的点,需要保证加上后权值要比二分值小,否则停止扩展,这样我们最多会扩展 \(k\) 次,然后我们可以用
__int128
来状压哪些点是可以加进当前团的。
代码用的是第一种实现方法。
代码:
#include<iostream>
#include<bits/stdc++.h>
#include<cstdio>
#include<algorithm>
#include<bitset>
#include<queue>
#define ll long long
#define N 110
using namespace std;
bitset<110> v[N];
template<typename T> inline void read(T &x){
x=0;int flag=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') flag*=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=flag;
}
struct Node{
ll val;
bitset<110> bit;
inline Node(){}
inline bool operator < (const Node &b)const{
return val<b.val;
}
};
multiset<Node> S;
int n,k,a[N],cnt;
char s[N];
inline void Init(){
read(n);read(k);k--;
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=n;j++){
v[i][j]=s[j]-'0';
}
}
for(int i=1;i<=n;i++){
Node now;now.bit.reset();
now.bit[i]=1;now.val=a[i];
S.insert(now);
}
}
int main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
Init();
while(S.size()){
Node Top=(*S.begin());S.erase(S.begin());
cnt++;
if(cnt==k){
printf("%lld",Top.val);return 0;
}
int posi=-1;
for(int i=1;i<=n;i++) if(Top.bit[i]) posi=i+1;
while(S.size()+cnt>k) S.erase(--S.end());
for(int j=posi;j<=n;j++){
if((v[j]&Top.bit)==Top.bit&&(!(S.size()+cnt>k&&Top.val+a[j]>=(*(--S.end())).val))){
Top.bit[j]=1;Top.val+=a[j];
S.insert(Top);
Top.bit[j]=0;Top.val-=a[j];
}
}
}
puts("-1");
return 0;
}
T2
我们首先考虑 \(a_i\) 一定是 \(b_{i-2},b_{i-1},b_i\) 中的一个值,原因是我们只是需要一个相对大小,我们总可以调整调整这个值使其变成 \(b\) 中的值,当然是有解的情况下。所以我们每个位置都有三个取值。设 \(f_{i,j,k}\) 表示 \(i\) 这个数放第 \(i\) 个取值,\(j\) 这个数放第 \(k\) 个取值,是否有解,转移即可。代码实现略有技巧。
代码:
#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 100010
#define M number
using namespace std;
const int INF=0x3f3f3f3f;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
inline int GetMid(int a,int b,int c){
if(a>b) swap(a,b);if(b>c) swap(b,c);if(a>b) swap(a,b);
return b;
}
int b[N],t,n,a[N][3],Pre[N][3][3],ans[N];
bool f[N][3][3];
inline void Clear(){
for(int i=1;i<=n;i++){
for(int j=0;j<=2;j++) for(int k=0;k<=2;k++){
f[i][j][k]=0;Pre[i][j][k]=-1;
}
}
}
inline void Init(){
read(n);
for(int i=3;i<=n;i++) read(b[i]);
b[1]=b[2]=b[3];
b[n+1]=b[n+2]=b[n];
for(int i=1;i<=n;i++){
a[i][0]=b[i];a[i][1]=b[i+1];a[i][2]=b[i+2];
// printf("a[%d][0]=%d a[%d][1]=%d a[2][%d]=%d\n",i,a[i][0],i,a[i][1],i,a[i][2]);
}
for(int i=1;i<=2;i++) for(int j=0;j<=2;j++) for(int k=0;k<=2;k++) f[i][j][k]=1;
}
inline void Solve(){
for(int i=3;i<=n;i++)
for(int j=0;j<=2;j++)
for(int k=0;k<=2;k++){
if(!f[i-1][k][j]) continue;
for(int l=0;l<=2;l++){
if(GetMid(a[i][l],a[i-1][k],a[i-2][j])!=b[i]) continue;
f[i][l][k]=1;Pre[i][l][k]=j;
// printf("f[%d][%d][%d]=%d\n",i-1,k,j,f[i-1][k][j]);
// printf("f[%d][%d][%d]=%d\n",i,l,k,f[i][l][k]);
// printf("Pre[%d][%d][%d]=%d\n",i,l,k,Pre[i][l][k]);
}
}
int nowj=-1,nowk=-1;
for(int j=0;j<=2;j++) for(int k=0;k<=2;k++) if(f[n][j][k]){nowj=j;nowk=k;break;}
// printf("nowj=%d nowk=%d\n",nowj,nowk);
if(nowj==-1&&nowk==-1) return(void)puts("-1");
int now=n;
while(nowj!=-1&&nowk!=-1){
ans[now]=a[now][nowj];
// printf("a[%d][%d]=%d\n",now,nowj,a[now][nowj]);
int Next=Pre[now][nowj][nowk];nowj=nowk;nowk=Next;now--;
// printf("Next=%d\n",Next);
if(Next==-1){
ans[now]=a[now][nowk];break;
}
}
ans[1]=b[1];
for(int i=1;i<=n;i++) printf("%d ",ans[i]);puts("");
}
int main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
memset(f,0,sizeof(f));memset(Pre,-1,sizeof(Pre));
read(t);
while(t--){
Init();Solve();Clear();
}
return 0;
}
T3,T4 因为考得不是 NOIP 内容,所以暂且先不补了。