写了三个题结果C fst了O.0
A - Boboniu Likes to Color Balls
回文串,最多有球是一个奇数个。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
IO;
int T;
cin>>T;
while(T--)
{
int a,b,c,d;
cin>>a>>b>>c>>d;
int cnt=(a&1)+(b&1)+(c&1)+(d&1);
if(cnt==0||cnt==1||cnt==4) cout<<"Yes"<<endl;//如果全是4个奇数可以用rgb换一个w,那么就变成全是偶数个
else if(cnt==2) cout<<"No"<<endl;
else
{
if(a*b*c) cout<<"Yes"<<endl;
else cout<<"No"<<endl;//说明rgb中有球的个数是0 不能换球
}
}
return 0;
}
B - Boboniu Plays Chess
直接模拟,一行一行走,先走完最初所在的行,然后从第一行开始S型走
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=210;
int n,m;
int u,v;
bool st[N];
int main()
{
IO;
cin>>n>>m;
cin>>u>>v;
cout<<u<<" "<<v<<endl;
st[u]=1;
for(int i=1;i<=m;i++)
if(i!=v) cout<<u<<" "<<i<<endl;
int v=m;
for(int i=1;i<=n;i++)
{
if(st[i]) continue;
st[i]=1;
if(v==m)
{
for(int j=m;j;j--)
cout<<i<<" "<<j<<endl;
v=1;
}
else
{
for(int j=1;j<=m;j++)
cout<<i<<" "<<j<<endl;
v=m;
}
}
return 0;
}
C - Boboniu and Bit Operations
贪心的取
c
i
c_i
ci最小最终OR最小不正确。如果某一位必须是1,那么其他
c
i
c_i
ci的该位是否为1就不重要了。
最开始想用trie树实现贪心
c
i
c_i
ci,结果后来一想不正确,就随便写了个dp没想的过了???(结果还是被FST
原因还是上述贪心方法不正确。
FST代码—— O ( n 3 ) O(n^3) O(n3)
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=210;
int a[N],b[N];
int n,m;
int f[N][N];
int main()
{
IO;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) cin>>b[i];
memset(f,0x3f,sizeof f);
for(int i=1;i<=m;i++) f[0][i]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=j;k++) f[i][j]=min(f[i][j],f[i-1][j]|(a[i]&b[k]));
cout<<f[n][m]<<endl;
return 0;
}
正解是枚举答案。我也想过枚举答案可是不知道怎么判断答案是否复合tcl。
如果枚举答案
k
k
k,那么对于每一个
a
i
a_i
ai都能找一个
b
j
b_j
bj使得a[i]&b[j]
二进制中1出现的位置答案中必须也出现,即(a[i]&b[j])|k==k
,一一判断即可
正解—— O ( 2 9 n m ) O(2^9nm) O(29nm)
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N=210;
int a[N],b[N];
int n,m;
int main()
{
IO;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) cin>>b[i];
for(int k=0;k<1<<9;k++)
{
bool ok1=1;
for(int i=1;i<=n;i++)
{
bool ok2=0;
for(int j=1;j<=m;j++)
if(((a[i]&b[j])|k)==k)
{
ok2=1;
break;
}
if(!ok2)
{
ok1=0;
break;
}
}
if(ok1) return cout<<k<<'\n',0;
}
}
D - Boboniu Chats with Du
复制数组!!!
分析题目可以简化成如果
a
i
<
=
m
a_i<=m
ai<=m那么代价是
1
1
1,如果
a
i
>
m
a_i>m
ai>m代价是
d
+
1
d+1
d+1很明显是一个01背包,不过数据范围。。。
从集合角度考虑:不妨让小于等于m的放在a[]
数组并逆序,大于m放在b[]
数组同样逆序,最终的答案一定是a[]
数组选出前i
个,从b[]
数组选出前j
个。因此我们可以枚举从b[]
数组选择了多少个,然后剩余的从a[]
数组选即可。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N=100010;
ll a[N],b[N];
int cnta,cntb;
int n,d;
ll m;
int main()
{
IO;
cin>>n>>d>>m;
for(int i=1;i<=n;i++)
{
ll x;
cin>>x;
if(x>m) b[++cntb]=x;
else a[++cnta]=x;
}
sort(a+1,a+1+cnta);
sort(b+1,b+1+cntb);
reverse(a+1,a+1+cnta);
reverse(b+1,b+1+cntb);
for(int i=1;i<=cnta;i++) a[i]+=a[i-1];
for(int i=cnta+1;i<=n;i++) a[i]=a[i-1];//这个地方非常dt 需要赋值一份
for(int i=1;i<=cntb;i++) b[i]+=b[i-1];
ll res=0;
int cntm=min(cntb,(n+d)/(d+1));
for(int k=0;k<=cntm;k++)
{//如果不进行上述复制操作 如果n-(d+1)*(k-1)-1>cnt a[n-(d+1)*(k-1)-1]=0 理论应该是所有a[cnta]
ll now=b[k];
if(k) now+=a[n-(d+1)*(k-1)-1];//如果不进行上述复制那么now+=a[min(cnta,n-(d+1)*(k-1)-1]
else now+=a[n];//now+=a[cnta]
res=max(res,now);
}
cout<<res<<endl;
return 0;
}
emm~~看E群里面讨论的很难 随缘补吧。要加油哦!