9/12 思维训练

C. Digital Logarithm
使用优先队列模拟这个元素消去的过程。

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+5;
const int inf=1e18;
const int mod=1e9+7;
int fac[40];
int qpow(int a,int b){
    int res=1;
    while(b)
    {
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int getinv(int x){return qpow(x,mod-2);}
int C(int a,int b)
{
    return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
}

int n;
priority_queue<int>a,b;
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        int x;cin>>x;
        a.push(x);
    }
    for(int i=1;i<=n;i++){
        int x;cin>>x;
        b.push(x);
    }
    int ans=0;
    while(!a.empty()&&!b.empty())
    {
        int x=a.top();
        int y=b.top();
        if(x==y)
        {
            a.pop();b.pop();continue;
        }
        ans++;
        if(x>y)
        {
            a.pop();
            a.push(to_string(x).length());
        }
        else
        {
            b.pop();
            b.push(to_string(y).length());
        }
    }
    cout<<ans<<endl;
}
signed main()
{
    //ios;
    int T;cin>>T;
    while(T--)
        solve();
    return 0;
}

G. Good Key, Bad Key
假设两个箱子x和y:
先好钥匙开x再坏钥匙开y:x-k+y/2
先坏要是开x再好钥匙开y: x/2+y/2-k
因此可发现坏要是后面不能接好钥匙,只能接坏钥匙。
暴力求解从何处开始只开坏箱子。

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+5;
const int inf=1e18;
const int mod=1e9+7;
int fac[40];
int qpow(int a,int b){
    int res=1;
    while(b)
    {
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int getinv(int x){return qpow(x,mod-2);}
int C(int a,int b)
{
    return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
}
int n,k,a[N];
void solve()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    int ans=0,sum=0;
    for(int i=1;i<=n;i++)
    {
        int tp=sum;
        for(int j=i;j<=min(i+32,n);j++)
        {
            int g=a[j];
            g>>=j-i+1;
            tp+=g;
        }
        ans=max(ans,tp);
        sum+=a[i]-k;
    }
    ans=max(ans,sum);
    cout<<ans<<endl;
}
signed main()
{
    //ios;
    int T;cin>>T;
    while(T--)
        solve();
    return 0;
}

C. Infected Tree
简单树形dp,没写出来不应该。
状态转移方程:f[x]=max(f[x],f[y]+sz[x]-sz[y]-2);
删除一个分支节点,需要减去2(结点本身和子结点),加上被感染结点最多可保留的符合条件的节点数

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+5;
const int inf=1e18;
const int mod=1e9+7;
int fac[40];
int qpow(int a,int b){
    int res=1;
    while(b)
    {
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int getinv(int x){return qpow(x,mod-2);}
int C(int a,int b)
{
    return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
}
int n,ans,sz[N],f[N];
bool vis[N];
vector<int>e[N];
bool cmp(int a,int b){return a>b;}
void dfs(int x,int pre)
{
    sz[x]=1;
    for(int y:e[x])
    {
        if(y==pre) continue;
        dfs(y,x);
        sz[x]+=sz[y];
    }
    for(int y:e[x])
    {
        if(y==pre) continue;
        f[x]=max(f[x],f[y]+sz[x]-sz[y]-2);
    }
    for(int y:e[x])
    {
        if((pre==0&&e[x].size()==1)||(pre!=0&&e[x].size()==2))
           f[x]=max(f[x],sz[x]-2);
    }
}
void solve()
{
    cin>>n;
    for(int i=0;i<=n;i++)
        sz[i]=f[i]=0,e[i].clear();
    for(int i=1;i<n;i++)
    {
        int u,v;cin>>u>>v;
        e[u].push_back(v);e[v].push_back(u);
    }
    dfs(1,0);
    cout<<f[1]<<endl;

}
signed main()
{
    ios;
    int T;cin>>T;
    while(T--)
        solve();
    return 0;
}

C. Binary String
题意:在一个01字符串中,可从左右两端删除任意的字符,删除1的数目和字符串中0的数目去最大值,要求让这个最大值最小
思路:
s1表示任意字符串的长度,t1字符串中1的数目,t0表示任意字符串中1的数目
不细说了,最后可化简为s1-t1=t0,及求出字符’0‘的前缀和,保证这个差值最大即可,区间长度为1的数目。

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+5;
const int inf=1e18;
const int mod=1e9+7;
int fac[40];
int qpow(int a,int b){
    int res=1;
    while(b)
    {
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int getinv(int x){return qpow(x,mod-2);}
int C(int a,int b)
{
    return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
}
bool cmp(int a,int b){return a>b;}
int n,ans,sum[N];
bool vis[N];
vector<int>e[N];

void solve()
{
    string s;cin>>s;
    int g=count(s.begin(),s.end(),'1'),n=s.length();
    s=" "+s;
    for(int i=1;i<=n;i++)
    {
        sum[i]=sum[i-1]+(s[i]=='0');
    }
    int ans=g;
    for(int i=g;i<=n;i++)
        ans=min(ans,sum[i]-sum[i-g]);
    cout<<ans<<endl;
}
signed main()
{
    //ios;
    int T;cin>>T;
    while(T--)
        solve();
    return 0;
}

A. The Enchanted Forest
感谢队友对于本题数学公式的解释,妙啊
思路:
容易看出分为k<=n和k>n两种情况,每种情况都要考虑增加蘑菇;前者为k*(k-1)/2,后者由于肯定会经过这n个点,因此不妨走到一端后,变保持自己的位置不动,(保持不动我是真的没想到),但是蘑菇数还是再增加的,当实践还剩k-n秒时,我们就要去收割那些本来就有的蘑菇和长处的蘑菇了,此时租箱另一端,在这个过程中,本来保持不懂的端点长出了n个蘑菇踩不到,相邻的一个点有n-1个蘑菇踩不到……以此类推,总数为n*(n+1)/2个蘑菇踩不到。

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+5;
const int inf=1e18;
const int mod=1e9+7;
int fac[40];
int qpow(int a,int b){
    int res=1;
    while(b)
    {
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int getinv(int x){return qpow(x,mod-2);}
int C(int a,int b)
{
    return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
}
bool cmp(int a,int b){return a>b;}
int n,k,ans,sum[N],a[N];
bool vis[N];
vector<int>e[N];

void solve()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        sum[i]=sum[i-1]+a[i];
    }
    int ans=0;
    if(k<=n)
    {
        for(int i=k;i<=n;i++)
            ans=max(ans,sum[i]-sum[i-k]+k*(k-1)/2);
    }
    else
        ans=sum[n]+k*n-n*(n+1)/2;
    cout<<ans<<endl;
}
signed main()
{
    //ios;
    int T;cin>>T;
    while(T--)
        solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值