题意:两个汉堡和一块肌肉合成一个鸡肉汉堡,两个汉堡和一块牛肉合成一个牛肉堡
思路:暴力枚举,鸡肉堡和牛肉堡的个数
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define int long long
int s[3005][3005];
void solve(){
int n,a,b;
cin>>n>>a>>b;
int x,y;
cin>>x>>y;
int ans=0;
for (int i = 0; i <=a ; ++i) {
for (int j = 0; j <=b ; ++j) {
if(2*i+2*j<=n){
ans=max(ans,x*i+y*j);
}
}
}
cout<<ans<<endl;
}
signed main(){
int t;
cin>>t;
while(t--){
solve();
}
}
题意:你可以将一个全是0的图进行转换,每次转换是将一2 * 2的局部矩阵转为1,问你能否在有限次操作下,将矩阵转换成给的那样
思路:暴力枚举即可,当区域内出现一个0时,那我们就不转换,其他的情况转换,最后我们检查一下两张图是否一致,记得记录一下转换的过程
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define int long long
int g[55][55];
int s[55][55];
int n,m;
void print( int x,int y){
s[x][y]=1;
s[x+1][y]=1;
s[x][y+1]=1;
s[x+1][y+1]=1;
}
void printf(){
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=m ; ++j) {
cout<<s[i][j]<<' ';
}
cout<<endl;
}
cout<<endl;
}
void solve(){
cin>>n>>m;
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=m ; ++j) {
cin>>g[i][j];
}
}
vector<pair<int,int>>ans;
for (int i = 1; i <n ; ++i) {
for (int j = 1; j <m ; ++j) {
if(g[i][j]==1){
if(s[i][j]==0){
print(i,j);
ans.push_back({i,j});
// printf();
}
else if(g[i+1][j]==0||g[i][j+1]==0||g[i+1][j+1]==0){
continue;
}
else {
print(i,j);
ans.push_back({i,j});
// printf();
}
}
}
}
int vis=1;
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=m ; ++j) {
if(s[i][j]!=g[i][j]){
cout<<"-1";
return;
}
}
}
cout<<ans.size()<<endl;
for (auto i:ans) {
cout<<i.first<<' '<<i.second<<endl;
}
}
signed main(){
int t=1;
// cin>>t;
while(t--){
solve();
}
}
题意:修建一个运输石油的管道,1代表十字路口,1米管道的钱是a,一米支架的费用是b,问如何修建会使花费的费用最低,求出最低费用。
思路:可以考虑贪心,先把他们修成全在上面的那种,然后对01这种位置考虑贪心,如果放下会价格低多少费用,需记录多个0的总费用,第二个思路比较简单实现,DP动态规划,F(i,j)表示第i个当前的状态为j时,所需费用最低是多少,当si为0时,我们就可以推出f[i+1,0]是由两种方式转移来的,一种是f[i,0],一种是f[i,1],同理,f[i+1,1]也是两种转移来的,如果si是1时,这个i只有一种状态,就是f[i,1],没有0状态,只能推出i+1,1是由f[i,1]转移而来的,最后求出f[n,0]:
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n,a,b;
cin>>n>>a>>b;
string s;
cin>>s;
vector<vector<int>>f(n+4,vector<int>(2));
for (int i = 0; i <=n ; ++i) {
for (int j = 0; j <2 ; ++j) {
f[i][j]=1e18;
}
}
f[0][0]=b;
for (int i = 0; i <n ; ++i) {
if(s[i]=='0'){
f[i+1][0]=min(f[i][0]+a+b,f[i+1][0]);
f[i+1][0]=min(f[i+1][0],f[i][1]+2*a+b);
f[i+1][1]=min(f[i][0]+2*a+2*b,f[i+1][1]);
f[i+1][1]=min(f[i+1][1],f[i][1]+a+2*b);
}
else{
f[i+1][1]=min(f[i+1][1],f[i][1]+a+2*b);
}
}
cout<<f[n][0]<<endl;
}
signed main(){
int t=1;
cin>>t;
while(t--){
solve();
}
}
题意:给n个二元组,任意排序,如果第一个元素或者第二个元素组成的序列是非递减的序列,那么这个数组是坏数组,问好的情况是多少个
思路:总共是n!种情况,有三类是坏的,第一元素是坏的,第二元素是坏的,第一第二元素都是坏的,那我们根据容斥原理求出第一种,第二种,还有第三种,我们第一种加上第二种,减去第三种,我们就可以得到所有不重复的坏的方案个数,我们怎么求呢,考虑到当我们排序之后,保证他是坏的,那么他还是有序的,因此我们能够交换的是相等的数字的位置,假设有3个3,那么可以有3!个,所以我们就记录数字个数即可,然后我们求他们的交集,即排序第一个元素之后,我们可以检查第二个元素是不是坏的,如果不是坏的,那么没有交集,如果有坏的,我们可以记录一下一个pair<>,然后再求一遍!,最后减去即可
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define int long long
int fac[300005];
const int mod=998244353;
bool cmp1(pair<int,int>x,pair<int,int>y){
if(x.first!=y.first)
return x.first<y.first;
return x.second<y.second;
}
#define PII pair<int,int>
bool cmp2(pair<int,int>x,pair<int,int>y){
return x.second<y.second;
}
pair<int,int> a[300005];
map<int,int>vis1,vis2;
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n;
cin>>n;
fac[0]=1;
for (int i = 1; i <=n ; ++i) {
fac[i]=(fac[i-1]*i)%mod;
}
for(int i=1;i<=n;i++){
cin>>a[i].first>>a[i].second;
vis1[a[i].first]++;
vis2[a[i].second]++;
}
for (int i = 1; i <=n ; ++i) {
if(vis1[a[i].first]==n||vis2[a[i].second]==n){
cout<<"0";
return 0;
}
}
int ans1=1;
for (int i = 1; i <=n ; ++i) {
if(vis1[i])
ans1=(ans1*fac[vis1[i]]%mod)%mod;
}
int ans2=1;
for (int i = 1; i <=n ; ++i) {
if(vis2[i]){
ans2=(ans2*fac[vis2[i]]%mod)%mod;
}
}
int res=(ans1%mod+ans2%mod)%mod;
sort(a+1,a+1+n,cmp1);
for (int i = 2; i <=n ; ++i) {
if(a[i].second<a[i-1].second){
cout<<((fac[n]-res)%mod+mod)%mod;
return 0;
}
}
map<PII,int>mp;
int ans=1;
for (int i = 1; i <=n ; ++i) {
mp[{a[i].first,a[i].second}]++;
}
for (auto i:mp) {
ans=(ans%mod*fac[i.second]%mod)%mod;
}
cout<<((fac[n]-res+ans)%mod+mod)%mod;
}
题意:我们这是一个交互题,你要找出一个数x,在0到2^14-1之间,你可以询问两次,你每次询问是给出100个不同的数字,它反馈一个答案ans,这个答案是x与这100个数字的某个数字进行异或得到的,让你求出x
思路:假设我们第一次给出的数字是1到100,所有数的前7位二进制都是0,那么我们这个ans的前七位,即是x的前七位,然后我们让11111110000000与ans取&并集,即可以得到x的前七位,同理我们取后七位是0000000的数字,我们就可以求出后七位,然后我们取|即可以加起来
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
}
signed main(){
// ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cout<<"?";
for (int i = 1; i <=100 ; ++i) {
cout<<" "<<i;
}
cout<<endl;
::fflush(stdout);
int x;
cin>>x;
cout<<'?';
for (int i = 1; i <=100 ; ++i) {
cout<<' '<<(i<<7);
}
cout<<endl;
::fflush(stdout);
int y;
cin>>y;
// ::fflush(stdout);
int res=0;
res|=(x&(((1<<7)-1)<<7));
res|=(y&((1<<7)-1));
cout<<"! ";
cout<<res<<endl;
::fflush(stdout);
}
题意:两个操作,1操作是将a[x]+y,2操作是求i%x==y的a[i]的所有数字的和
思路:如果暴力的话是O(q * 500000),我们可以考虑分块,操作1时,我们可设一个数组ans[i][j],表示%x余y的数的和,那我们就可以对1-700每一个[i]进行遍历,求出%i余x%i的和,当我们进行操作2时,x<=700时,我们直接输出ans[x][y],如果大于700,我们可以进行一个暴力求解,复杂度在700左右,因此我们的复杂度就成了q根号q,即可过
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
//#define int long long
void solve(){
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int q;
cin>>q;
vector<int>a(5e5+5);
vector<vector<int>>ans(705,vector<int>(705));
while (q--){
int x,y,op;
cin>>op>>x>>y;
if(op==1){
a[x]+=y;
for (int i = 1; i <=700 ; ++i) {
ans[i][x%i]+=y;
}
}
else{
if(x<=700)cout<<ans[x][y]<<'\n';
else{
int res=0;
for (int i = y; i <=(int)5e5+5 ; i+=x) {
res+=a[i];
}
cout<<res<<'\n';
}
}
}
}