原题链接:https://codeforces.com/contest/1207/problem/A
题意: 一个汉堡包需要由2个小面包+1个小的牛排组成,一个鸡肉汉堡需要由2个小面包+1个小鸡肉排组成。现在给你了小面包数 b,小牛排数 p,小鸡肉排数 f,已知一个汉堡包和一个鸡肉汉堡包的单价分别为 h,c。
问:组合小面包和小牛排和小鸡肉排使得卖的价值最大,输出最大价值。
思路: 贪心题,先组合单价高的食物,剩下的再来组单价低的食物。
Code(C++):
#include
using namespace std;
int main(){
int t; cin>>t;
while(t--){
int b,p,f; cin>>b>>p>>f;
int h,c; cin>>h>>c;
int ans=0;
//把h确定为单价高的食物,相应的数量也要交换
if(h<c) swap(h,c),swap(p,f);
b/=2;
int t=min(b,p);
ans+=h*t;
b-=t;
t=min(b,f);
ans+=c*t;
cout<<ans<<endl;
}
return 0;
}
原题链接: https://codeforces.com/contest/1207/problem/B
题意: 给一个二维矩阵 A,B 矩阵全是0,每次可以在 B 矩阵里指定一个 2x2 的矩阵全部变为1。问最终能否使得 B 矩阵等于 A 矩阵,可以的话输出操作次数以及指定的每个 2x2 小矩阵的左上角的点的坐标;不可以的话输出 -1。
思路: 用二维数组 a[i][j] 存目标矩阵,二维数组 b[i][j] 存每个指定的小矩阵左上角的点的坐标,二维数组 c[i][j] 存改变后的矩阵。最后比较二维数组 a[i][j] 是否完全等于二维数组 c[i][j] 。
Code(C++):
#include
using namespace std;
const int maxn=100;
int a[maxn][maxn],b[maxn][maxn],c[maxn][maxn];
int main(){
int n,m; cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]==1 && a[i][j+1]==1 && a[i+1][j]==1 && a[i+1][j+1]==1){
b[i][j]=1;
ans++;
c[i][j]=c[i][j+1]=c[i+1][j]=c[i+1][j+1]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(c[i][j]!=a[i][j]){
cout<<-1<<endl;
return 0;
}
cout<<ans<<endl;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(b[i][j])
cout<<i<<" "<<j<<endl;
return 0;
}
原题链接: https://codeforces.com/contest/1207/problem/C
题意: 题意还是挺难理解的。有一条路,除了首尾,中间可能会有一些十字路口,而你需要设置一些管道,当有十字路口时需要抬升,不同的方案造价不同,给与管道与柱子的花费,给出最小开销。
思路: 动态规划,用dp[i][0]表示到第 i 个路口为低柱子时所需要的最低花费,dp[i][1]第 i 个路口为高柱子所需要的最低花费。具体见代码。
Code(C++):
#include
#define inf 0x3f3f3f3f
using namespace std;
const int N=2e5+5;
typedef long long ll;
ll dp[N][2];
int main(){
int t; cin>>t;
while(t--){
ll n,a,b; cin>>n>>a>>b;
string s; cin>>s;
memset(dp,inf,sizeof(dp));
dp[0][0]=b; //一开始是低柱子,需要一根黑水管
for(int i=0;i<n;i++){
if(s[i]=='1') //如果是十字路口,那么右边只能是高柱子
dp[i+1][1]=dp[i][1]+a+b*2;
else{ //如果不是十字路口,那么右边可以是高柱子也可以是低柱子
dp[i+1][0]=min(dp[i][0]+a+b,dp[i][1]+a*2+b);
dp[i+1][1]=min(dp[i][0]+a*2+b*2,dp[i][1]+a+b*2);
}
}
cout<<dp[n][0]<<endl; //最后一定是低柱子
}
return 0;
}
原题链接: https://codeforces.com/contest/1207/problem/D
题意: 给你n个二元组,问有多少种排列能使得按二元组任意一个元素排列都不是不降排列的。
思路: 利用容斥原理,用全排列总数目减掉按第一个元素排列是非递减的数目,再减掉按第二个元素排列是非递减的数目,再加上以上两种情况的重叠部分。
Code(C++):
#include
#include
#include
#define PI acos(-1)
#define sec second
#define pai pair
#define ll long long
using namespace std;
const int mod=998244353;
const int maxn=3e5+10;
map<int,int> a,b;
map<pai,int> ab;
pai s[maxn];
ll fac[maxn];
int main(){
int n; cin>>n;
fac[0]=1;
for(int i=1;i<=n;++i) //全排列所有数目
fac[i]=fac[i-1]*i%mod;
int x,y;
for(int i=1;i<=n;++i){
cin>>x>>y;
a[x]++,b[y]++,ab[{x,y}]++;
s[i]=make_pair(x,y);
}
sort(s+1,s+1+n);
ll ans=fac[n],temp=1;
for(auto i:a) //第一个元素的排列是非递减的全排列数目
temp=temp*fac[i.sec]%mod;
ans=(ans-temp+mod)%mod,temp=1;
for(auto i:b) //第二个元素的排列是非递减的全排列数目
temp=temp*fac[i.sec]%mod;
ans=(ans-temp+mod)%mod,temp=1;
for(auto i:ab) //前两种情况重叠的全排列数目
temp=temp*fac[i.sec]%mod;
for(int i=1;i<n;i++) //如果存在s[i+1].sec
if(s[i+1].sec<s[i].sec) temp=0;
ans=(ans+temp)%mod;
cout<<ans<<endl;
return 0;
}
原题链接: https://codeforces.com/contest/1207/problem/E
题意: 有一个数x(0 ~ 2^14-1),让你猜,你每次会提出两个询问,每次询问包含100个整数(这两百个整数必须不同),然后每次会给你两个输入,分别是数 x 异或询问中的某一个数的结果,求 x
思路: 最多可能是 214−1 总共14位数,最多可以询问两次,那么只需要分别求出其前 7 位和后 7 位即可。1 ~ 100 与 x 取 &,那么就可以得出 x 的前 7 位的值,因为 1 ~ 100 最多只有 7 位,不会影响到前 7 位,那么后 7 位只需将 x 与(1~100)<<7 取 & 即可。
Code(C++):
#include
using namespace std;
int main(){
cout<<"?";
for(int i=1;i<=100;i++)
cout<<" "<<i;
cout<<endl;
int x; cin>>x;
cout<<"?";
for(int i=0;i<100;i++)
cout<<" "<<(i+1<<7);
cout<<endl;
int y; cin>>y;
cout<<"! "<<((y&0x7f)|(x&~0x7f))<<endl;
return 0;
}