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

题目链接

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

B-Binary Vector

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

猜公式:

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

#include
#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
#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

 

C-Combination of Physics and Maths

 

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

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

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

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

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

 

#include
#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
#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

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

题意:给你  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
#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
#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

 

G-Grid Coloring

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

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

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

#include
#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
#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

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

题意:求 (A,B)的个数 使得A的十进制下每位数的和大于B的十进制下每位数的和。

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

#include
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

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

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

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

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

#include
#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
#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 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=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

*/

 

你可能感兴趣的:(牛客题解,dp---数位DP)