B. Flipping Game

题意:

给一个n大小的01串,可以进行k次操作,0代表关灯,1代表开灯,每次操作是对m个灯进行取反,问最后一次操作后可以成为目标的串,这个方案有多少个?

思路: DP,我们考虑$f[i][j]$表示进行i次操作,有j个灯与目标状态不同的方案数,当我们求这一层的$f[i][j]$的方案数时,它是由上一层转移过来的,我们枚举l,代表第i次操作时我们改变了l个与目标状态不同的灯然后由上一层的j状态转移到了当前层的g状态,$g=j-l+(m-l)$,当前层就是$f[i][j+m-2*l]$那么我们就要保证$j+m- 2 * l>=0$, 并且$n-j>=m-l$,然后我们操作的m个灯,有l个是不等变为等,有m-l个是等变为不等,那么我们在j里面取l个,在n-j里面取m-l个,就可以转移:


状态转移方程式:

$ f[i][j]=(f[i][j]+f[i-1][j+m-2 * l] * C(j)l * C(n-j)(m-1))$,别忘了取模。

细节:组合数预处理100以内的,不然直接求的话会超时,卢卡斯求,暴力求都可以,初始化为f[0][s]=0,s代表出状态不等的个数,答案即是f[k][0]。

代码:

#include<bits/stdc++.h>
using namespace  std;
#define int long long
#define LL long long
#define pii pair<int,int>
struct node{
    int l,r;
}a[100010];
bool cmp(node x,node y){
    return x.r<y.r;
}
const int mod=998244353;
//若p是质数,则对于任意整数 1 <= m <= n,有:
//C(n, m) = C(n % p, m % p) * C(n / p, m / p) (mod p)
map<pair<int,int>,int>mp;
int qmi(int a, int k, int p) {  // 快速幂模板
    int res = 1 % p;
    while (k) {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}

int C(int a, int b, int p) {  // 通过定理求组合数C(a, b)
    if (a < b) return 0;

    LL x = 1, y = 1;  // x是分子,y是分母
    for (int i = a, j = 1; j <= b; i --, j ++ ) {
        x = (LL)x * i % p;
        y = (LL) y * j % p;
    }

    return x * (LL)qmi(y, p - 2, p) % p;
}

int lucas(LL a, LL b, int p) {
    if (a < p && b < p) return C(a, b, p);
    return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}

void solve(){
    int n,m,k;
    cin>>n>>k>>m;
    string s1,s2;
    cin>>s1>>s2;
    int s=0;
    for (int i = 0; i <s2.size() ; ++i) {
        if(s2[i]!=s1[i])s++;
    }
    vector<vector<int>>f(k+5,vector<int>(n+5));
    f[0][s]=1;

    for (int i = 1; i <=k ; ++i) {
        for (int j = 0; j <=n ; ++j) {
            if(f[i-1][j]==0)continue;
            for (int l = 0; l <=m ; ++l) {
                if(j>=2*l-m&&n-j>=m-l){
//                    f[i][j+m-2*l]=(f[i][j+m-2*l]+(C(j,l,mod)%mod*C(n-j,m-l,mod)*f[i-1][j])%mod)%mod;
                    f[i][j+m-2*l]=(f[i][j+m-2*l]%mod+(mp[{j,l}]%mod*mp[{n-j,m-l}]%mod*f[i-1][j])%mod)%mod;
                }
            }
        }
    }
//    for (int i = 1; i <=k ; ++i) {
//        cout<<i<<':';
//        for (int j = 0; j <=n; ++j) {
//            cout<<f[i][j]<<' ';
//        }
//        cout<<endl;
//    }

    cout<<f[k][0]%mod<<'\n';

}
signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
    int t;
    cin>>t;
    for (int i = 0; i <=100 ; ++i) {
        for (int j = 0; j <=i ; ++j) {
            mp[{i,j}]= C(i,j,mod);
        }
    }
    while (t--){
        solve();
    }
}

F. Stones in the Bucket

题意:地面上有n个水桶,其中第i个水桶装有ai块石头。每次可以进行以下两种操作之一:

  • 从一个非空桶中移走一块石头。
  • 从其中一个桶(必须是非空的)中移动一块石头到其他任何一个桶(可以是空的)。
  • 要使所有水桶中的石子数量相同,最少需要进行多少次操作?

    思路:求一下最终的平均值,然后遍历一遍,当小于平均值,则进行操作二,最后再进行操作一,抹去多的

    代码:

    #include<bits/stdc++.h>
    using namespace  std;
    #define int long long
    #define pii pair<int,int>
    void solve(){
    int n;
    cin>>n;
    vector<int >q(n+1);
    int s=0;
    for (int i = 1; i <=n ; ++i) {
        cin>>q[i];
        s+=q[i];
    }
    int sum=0;
    int d=s%n;
    int dd=s/n;
    for(int i=1;i<=n;i++){
        if(q[i]<dd){
            sum+=dd-q[i];
        }
    }
    sum+=d;
    cout<<sum<<endl;
    }
    signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
    int t;
    cin>>t;
    while (t--){
        solve();
    }
    }

    L. Median

    题意:一个数组是n大小的,给m条线索,x-y代表a[y]大于a[x],问满足这m条线索能否有一个中位数存在,中位数的位置标为1,其他位置为0;

    思路:数据范围较小,直接正向建边,反向建边,然后枚举起点,从起点跑到终点,如果不存在环,且正反跑到的数字都小于等于n/2,那么这个位置就可以作为中位数

    代码:

    #include<bits/stdc++.h>
    using namespace  std;
    //#define int long long
    #define LL long long
    #define pii pair<int,int>
    struct node{
    int l,r;
    }a[100010];
    bool cmp(node x,node y){
    return x.r<y.r;
    }
    const int mod=998244353;
    void solve(){
    int n,m;
    cin>>n>>m;
    vector<int>mp1[n+1],mp2[n+1];
    for (int i = 0; i <m ; ++i) {
        int x,y;
        cin>>x>>y;
        mp1[x].push_back(y);
        mp2[y].push_back(x);
    }
    auto bfs1=[&](int s){
        set<int> stt;
        stt.insert(s);
        queue<int >q;
        q.push(s);
        while (q.size()){
            auto t=q.front();
            q.pop();
            for (auto i:mp1[t]) {
                if(i==s){
                    return n;
                }
                else if(stt.count(i)==0){
                    stt.insert(i);
                    q.push(i);
                }
            }
        }
        return (int)stt.size()-1;
    };
    auto bfs2=[&](int s){
        set<int> stt;
        stt.insert(s);
        queue<int >q;
        q.push(s);
        while (q.size()){
            auto t=q.front();
            q.pop();
            for (auto i:mp2[t]) {
                if(i==s){
                    return n;
                }
                else if(stt.count(i)==0){
                    stt.insert(i);
                    q.push(i);
                }
            }
        }
        return (int)stt.size()-1;
    };
    int p=-1;
    vector<int>res;
    int da;
    int xiao;
    for (int i = 1; i <=n ; ++i) {
        da=bfs1(i);
        xiao=bfs2(i);
        if(da==n||xiao==n)break;
        if(da<=n/2&&xiao<=n/2){
            res.push_back(1);
        }
        else res.push_back(0);
    }
    if(da==n||xiao==n){
        for (int i = 0; i <n ; ++i) {
            cout<<'0';
        }
        cout<<'\n';
    }
    else{
        for (auto i:res) {
            cout<<i;
        }
        cout<<'\n';
    }
    }
    signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
    int t;
    cin>>t;
    while (t--){
        solve();
    }
    }

B. Grid with Arrows

题意:给一个n * m的图,给出每个点的下一步的方向,然后给出走的步长是多少,问有没有一种可能在某点出发,可以遍历到全图

思路:两种情况,一种是这个图是个环,一种是一条链,局部有环。

  • 第一种情况直接随便选个点跑一遍图,如果能够跑n * m个点,那么就yes
  • 第二种情况是从入度为0的点开始跑,跑完全图就是yes,其他是no

    diamond:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int mod=1e9+7;
    int fa[100005];
    int n,m;
    //int find(int x){
    // if(fa[x]!=x){
    // fa[x]=find(fa[x]);
    // }
    // return fa[x];
    //}
    //void merge(int x,int y){
    // int dx=find(x),dy=find(y);
    // fa[dy]=dx;
    //}
    int get(int x,int y){
    return (int)x*m+y;
    }
    void solve(){
    int cnt=0;
    cin>>n>>m;
    // vector<int>vis(n*m);
    vector<int>g[(n+1)*(m+1)];
    vector<string>s(n+4);
    for (int i = 0; i <n ; ++i) {
        cin>>s[i];
    }
    vector<int>du(n*m+5,0);
    int dian;
    int st=0;
    for (int i = 0; i <n ; ++i) {
        for (int j = 0; j <m ; ++j) {
            int q;
            cin>>q;
            int x=i,y=j;
            int xx = 0,yy=0;
            if(s[x][y]=='r'){
                yy=y+q;
                xx=x;
            }
            else if(s[x][y]=='l'){
                yy=y-q;
                xx=x;
            }
            else if(s[x][y]=='u'){
                xx=x-q;
                yy=y;
            }
            else if(s[x][y]=='d'){
                xx=x+q;
                yy=y;
            }
            int a= get(x,y);
            int b= get(xx,yy);
    //            cout<<xx<<' '<<yy<<endl;
            if(xx<0||xx>=n||yy<0||yy>=m){
                continue;
            }
            else{
                g[a].push_back(b);
                du[b]++;
            }
        }
    }
    dian=-1;
    for (int i = 0; i <n*m ; ++i) {
        if(du[i]==0){
            dian=i;
            break;
        }
    }
    //    cout<<dian<<endl;
    if(dian==-1){
        dian=0;
    }
    vector<int>vis(n*m+5);
    
    function< void (int )> dfs2= [&](int u){
        vis[u]=1;
        for (auto i:g[u]) {
            if(!vis[i]){
                cnt++;
                dfs2(i);
            }
    
        }
    };
    cnt=1;
    vis[dian]=1;
    dfs2(dian);
    if(cnt==n*m){
        cout<<"Yes\n";
    }
    else{
        cout<<"No\n";
    }
    }
    signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while (t--){
        solve();
    }
    }

C.0689

题意:

一个字符串,仅有0、6、8、9组成,选取一个子串,翻转,得到新的字符串,问新得到的字符串不同的有多少个?0,8翻转还是自己,6翻转是9,9翻转是6。

思路:

如果每个数都不一样,那么翻转后不同的就应该是所有子串和自己,即(n+1) * n/2+1,我们把重复的减去,


去重,如果开头-末尾是0 - 0,8 -8 ,6 - 9,9 - 6,这些都是重复的比如0680,翻转0680,其实是翻转68,和开头结尾没关系,0 - 0的情况,是统计出0的个数,那么以0结尾的子串的个数就是(1+num) * num/2; 8-8也一样,


9-6和6-9的情况,统计出9的个数x,6的个数y,那么重复个数是x * y。


还有一个特例,如果全为6或者全为9,翻转后是必然得不到自己原来的状态的,那么ans就--;

diamond:

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
int mod;
int n,p;

void solve() {
    string s;
    cin>>s;
    int n=s.size();
    vector<int>num(4,0);
    for (int i = 0; i <n ; ++i) {
        if(s[i]=='0')num[0]++;
        else if(s[i]=='6')num[1]++;
        else if(s[i]=='8')num[2]++;
        else num[3]++;
    }
    int ans=(n+1)*n/2+1;
    ans-=(num[0]+1)*num[0]/2;
    ans-=(num[2]+1)*num[2]/2;
    ans-=num[1]*num[3];
    if(num[1]==n||num[3]==n)ans--;
    cout<<ans<<'\n';
}

signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;//
    while (t--){
        solve();
    }
}
posted on 2023-08-02 19:15  IR101  阅读(4)  评论(0编辑  收藏  举报  来源