2020牛客暑期多校训练营(第六场)(B 猜公式,C签到,E 构造模拟,G 简单模拟,H 数位dp,K dp)

题目链接

总结:今天日常低迷,今天我又包揽了所有题的AC,(悲伤),今天题都挺简单的,不知道为什么就是做不出,简单题都做不出,唉

B-Binary Vector

猜公式:

f(i)=\prod _{i=1}^n\frac{2^i-1}{2^i}

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb emplace_back
#define pii pair<int,int>
#define mk make_pair
using namespace std;
typedef long long ll;
 
const ll mod=1e9+7;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll powmod(ll a,ll b) {ll res=1;a%=mod;
assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
inline ll read()
{
    ll x=0,w=1; char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
    return w==1?x:-x;
}
const int N=2E7+10;
 
ll f2[N],dp[N],ans[N],fm[N];
int main()
{
    f2[1]=2;
    fm[1]=powmod(2,mod-2);
 
    for(int i=2;i<N;++i) {
        f2[i]=f2[i-1]*2%mod;
        fm[i]=fm[i-1]*fm[1]%mod;
    }
 
    ans[1]=fm[1];
    //cout<<fm[1]<<endl;
    for(int i=2;i<N;++i){
        ll fz=(f2[i]-1)%mod;
        ll tmp=fz*fm[i]%mod;
//        if(i<=5)
//        cout<<fz<<" "<<fm[i]<<endl;
 
        ans[i]=ans[i-1]*(f2[i]-1)%mod*fm[i]%mod ;
 
    }
    for(int i=2;i<N;++i) ans[i]=ans[i-1]^ans[i];
 
 
 
    int _=read();while(_--){
        int n=read();
        printf("%lld\n",ans[n]);
    }
}

 

C-Combination of Physics and Maths

 

题意:选择某几行以及某几列,F=所有a[i][j]的和,S是最下面一行所有a[i][j]的和,求P=F/S  的P 最大。

做法:队友看一眼 说什么 01整数划分模板题,然后过了10分钟没A出来,我看一眼,这不傻逼题吗?

简单分析 只需要一列就可以了,官方解释,跟我想的差不多吧

 

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb emplace_back
#define pii pair<int,int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
inline ll read()
{
	ll x=0,w=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
	return w==1?x:-x;
}
const int N=2e2+10;
typedef long double ld;
typedef long long ll;
int n,m;
double a[N][N];
int main()
{
    int _=read();while(_--){
        n=read(),m=read();
        rep(i,1,n){
            rep(j,1,m)
            scanf("%lf",&a[i][j]);
        }

        double ans=0;
        for(int j=1;j<=m;++j){
            double sum=0;
            int fz=0;
            for(int i=1;i<=n;++i){
                sum+=a[i][j];
                fz=a[i][j];
                //printf("sum:%f fz:%d tmp:%f\n",sum,fz,sum/fz);
                ans=max(ans,sum/fz);
            }
        }
        printf("%.9f\n",ans);
    }
}

 

E-Easy Construction

题意:给你  n,k 构造 排列,使得存在 i长度(1<=i<=n)的子区间序列和模n等于k

做法:如果排列1到n的和模k不等k,则无解,

否则分两种情况,

1、k==0   n  1  n-1 2 n-2 的放

2、k!=0  n,k,1 ,n-1,2,n-2...... n-k

 

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb emplace_back
#define pii pair<int,int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
inline ll read()
{
	ll x=0,w=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
	return w==1?x:-x;
}
const int N=5e5+10;
int n,k;
int a[N];

int vis[6000];
int main()
{
    int n=read(),k=read();
    int sum=n*(n+1)/2;
    if(sum%n!=k){
        puts("-1");
    }
    else{
        if(k==0){
            int i=1,j=n-1;
            printf("%d ",n);
            while(i<j){
                if(i!=k) printf("%d %d ",i,j);
                ++i,--j;
            }

            if(i==j) printf("%d ",i);

        }
        else{
            int i=1,j=n-1;
            printf("%d %d ",n,k);
            vis[n]=vis[k]=1;
            while(i<j){
                if(i!=k&&j!=k) printf("%d %d ",i,j);
                vis[i]=vis[j]=1;
                ++i,--j;
            }
            if(i==j&&!vis[i]) printf("%d ",i);
            if(!vis[n-k]) printf("%d ",n-k);
            //printf("%d ",n-k);
        }
    }


}

 

G-Grid Coloring

题意:给你n、k 代表n*n的格子,k种颜色,每个短棍 可以选择k种颜色的一个  涂颜色。

做法:每行 从 1 到k 连续染色就可以了,特判n==1  k==1的情况

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb emplace_back
#define pii pair<int,int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
inline ll read()
{
	ll x=0,w=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
	return w==1?x:-x;
}
const int N=4e2+10;
int a[N][N],n,k;
int main()
{
    int _=read();while(_--){
        n=read(),k=read();

        if(n==1||k==1){
            puts("-1");continue;
        }
        if(2*n*(n+1)%k!=0){
            puts("-1");continue;
        }
        int now=0;
        for(int i=1;i<=2*n+1;i++){
            if(i%2){
                for(int j=1;j<=n;++j) a[i][j]=now,now=(now+1)%k;
            }
            else{
                for(int j=1;j<=n+1;++j) a[i][j]=now,now=(now+1)%k;
            }
        }



        for(int i=1;i<=2*n+1;i+=2) {
            for(int j=1;j<=n;++j)printf("%d ",a[i][j]+1);
            puts("");
        }
        for(int j=1;j<=n+1;++j)
        {
            for(int i=2;i<=2*n;i+=2)printf("%d ",a[i][j]+1);
            puts("");
        }
    }
}

H-Harmony Pairs

题意:给出n ,然后求出从0 到n 有多少个数对,满足第一个数小于第二个数,但是第一个数的各位之和要大于第二个数

做法:数位dp ,设 dp[id][d][l1][l2][l3] 为当前位id  第一个数A的数位和减去B的数位和,l1 l2 是限制上限  l3 是限制前id位 每位是相等的情况时的方案数

#include<bits/stdc++.h>
using namespace std;
const int N = 4e2 + 10;
typedef long long ll;
const ll mod = 1e9 + 7;
int a[N], n, base = 1000;
char s[N*10];
ll dp[200][2000][2][2][2];


ll dfs(int id, int d, int l1, int l2, int l3)
{

    if(id == n + 1) return d > base;

    if(dp[id][d][l1][l2][l3]!=-1) return dp[id][d][l1][l2][l3];


    int up1, up2;
    if(l1) up1 = a[id];
    else up1 = 9;
    if(l2) up2 = a[id];
    else up2 = 9;

    ll ans = 0;
    for(int i = 0; i <= up1; ++i){
        for(int j = 0; j <= up2; ++j){
            if(l3 && i <= j || !l3){
                //printf("i:%d j:%d\n", i, j);
                ans += dfs(id + 1, d + i - j, l1 && (i==up1), l2 && (j==up2), l3 && (i==j));
                ans %= mod;
            }
        }
    }
    return dp[id][d][l1][l2][l3] = ans;
}

int main()
{
    scanf("%s", s + 1);
    n = strlen(s + 1);
    memset(dp, -1, sizeof(dp));

    for(int i = 1; i <= n; ++i) a[i] = s[i] - '0';
    ll ans = dfs(1, base, 1, 1, 1);
    printf("%lld", ans);
    return 0;
}

K-Bag

题意:给你n长度排列,从后面加数 或从前面加数使得 得到的排列是每k个是一个 k排列

做法:dp,枚举合法的起点,然后用dp维护一下 终点的位置

首先预处理 第一次某个数出现两次的位置,前面的位置都是合法的起点,然后当前pos位 前k位如果是 k排列,pos-k 的位置是一个合法的位置,那么当前pos也是合法的位置,得到最后一位的位置时,再判断下后缀的数 是不是只出现了一次

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb emplace_back
#define pii pair<int,int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
inline ll read()
{
	ll x=0,w=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
	return w==1?x:-x;
}
const int N=5e5+10;
int a[N], f[N], n, k, l;
int main()
{

    int _=read();while (_--) {
        int n, k, l = 0;
        n = read(), k = read();
        rep(i, 1, n) a[i] = read(), f[i] = 0;
        unordered_map<int, int> mp;
        int ans=0;
        
        for(l=1;l<=n;++l){
            if(mp[a[l]]) break;
            if(mp[a[l]]==0) ans++;
            mp[a[l]]++;
//            if(mp[])
//            st.insert(a[l]);
        }


        for (int i=1;i<l;i++) f[i] = 1;
        for (int i=l;i<=min(n,k);i++) {
            if(mp[a[i]]==0) ans++;
            mp[a[i]]++;
        }

        for (int i=k+1,j=1;i<=n;++i,++j) {

            if(mp[a[j]]==1) ans--;
            mp[a[j]]--;
            //if (!mp[a[j]]) st.erase(a[j]);
            if(mp[a[i]]==0) ans++;
            mp[a[i]]++;
            //st.insert(a[i]);
            if (ans==k&&f[j]) f[i] = 1;
        }
        mp.clear();

        int flag=1;
        for(int r=n;r>=1&&!f[r]&&flag;--r){
            if(mp[a[r]]) flag=0;
            mp[a[r]]=1;
        }
        printf("%s\n",flag?"YES":"NO");
    }
    return 0;
}
/*
1
6 3
2 3 1 2 3 2

*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙大学ccsu_deer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值