A. There Are Two Types Of Burgers

题意:两个汉堡和一块肌肉合成一个鸡肉汉堡,两个汉堡和一块牛肉合成一个牛肉堡

思路:暴力枚举,鸡肉堡和牛肉堡的个数

代码:

#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();
    }

}

B. Square Filling

题意:你可以将一个全是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();
    }

}

C. Gas Pipeline

题意:修建一个运输石油的管道,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();
    }
}

D. Number Of Permutations

题意:给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;
}

E. XOR Guessing

题意:我们这是一个交互题,你要找出一个数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);
}

F. Remainder Problem

题意:两个操作,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';
            }
        }
    }

}
posted on 2023-07-25 10:46  IR101  阅读(8)  评论(0编辑  收藏  举报  来源