2022/4/1 思维

142 篇文章 1 订阅

今天真的是太废啦!!!!!!

Lusir的游戏

当前能量为e,如果e<h[i+1],那么e-(h[i+1]-e)=2e-h[i+1],否则e+e-h[i+1]=2e-h[i+1];所以无论是大于还是小于变化都是一样的,就按样例来说到最后的能量为32e-16h[1]-8h[2]-4h[3]-2h[4]-h[5],显然是和2的n次方有关系,但是由于数太大,我们把乘以2的n-i-1次方改为除以2的i次方,最后加起来向上取整就可以了;

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1000000007;
const ll inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a){return qpow(a,mod-2);}
ll n;
double h[100005];
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%lld",&n);
    double y=2,sum=0;
    for(int i=1;i<=n;i++){
        scanf("%lf",&h[i]),h[i]/=y;
        y*=2;
        sum+=h[i];
    }
    ll ans=ceil(sum);
    printf("%lld\n",ans);
	return 0;

 }

Get an Even String

最少删掉几个数也就是最大能保留多少数,用dp[i]代表前i个字符能保留多少个字符,dp[i]=max(dp[i],dp[last[s[i]]-1]+2);因为不能和上一对重复,所以last[s[i]]要减1;当时就是不知道如何来找这个字母的上一个位置,真是蠢到家了,用一个map就可以了呀,哎,,,

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1000000007;
const ll inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a){return qpow(a,mod-2);}
ll t,n,dp[200005];
map<char,int>mp;
string s;
int main(){
   // freopen("in.txt","r",stdin);
    scanf("%lld",&t);
    while(t--){
        cin>>s;n=s.size();
        s="0"+s;
        for(int i=0;i<=n;i++) dp[i]=0;
        mp.clear();
        for(int i=1;i<=n;i++){
            dp[i]=dp[i-1];
            if(mp[s[i]])
            dp[i]=max(dp[i],dp[mp[s[i]]-1]+2);
            mp[s[i]]=i;
        }
        printf("%lld\n",n-dp[n]);
    }
	return 0;
 
 }

Maximum Product Strikes Back

让c题搞得这题也没心态想了,越想情况越复杂,最后直接崩了,,,只有当多个2相乘才可以改变最大值为1的情况,统计一下前i个数字出现i的次数,然后再用一个数组记录一下记录每一段离i最远且使乘积不为负的位置(这个地方好难想,不会实现)

Codeforces Round #780 (Div. 3) - 知乎 (zhihu.com)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1000000007;
const ll inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a){return qpow(a,mod-2);}
ll t,n,a[200005],val[2]={0,-1},two[200005];
int main(){
   // freopen("in.txt","r",stdin);
    scanf("%lld",&t);
    while(t--){
        scanf("%lld",&n);
        ll l=0,r=n,cnt=0,maxx=0;
        val[0]=0,val[1]=-1;
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            two[i]=two[i-1];
            if(abs(a[i])==2) two[i]++;
            if(a[i]<0) cnt++;
            if(val[cnt%2]>=0){
                if(maxx<two[i]-two[val[cnt%2]]){
                    maxx=two[i]-two[val[cnt%2]];
                    l=val[cnt%2],r=n-i;
                }
            }
            if(a[i]==0){
                cnt=0;
                val[0]=-1;
                val[1]=-1;
            }
            if(val[cnt%2]==-1) val[cnt]=i;//记录每一段离i最远且使乘积不为负的位置
        }
        printf("%lld %lld\n",l,r);
    }
	return 0;

 }

Matrix and Shifts

只要看看对角线最多能有多少个1就可以,假设对角线最多有ans个1,整个矩阵有sum个1,那么答案就是对角线上0的个数加上除对角线外矩阵有1的个数,也就是sum+n-2*ans;

Codeforces Round #780 (Div. 3) C D E F - 知乎 (zhihu.com)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1000000007;
const ll inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a){return qpow(a,mod-2);}
ll t,n,a[2005][2005];
char ch[2005][2005];
int main(){
   // freopen("in.txt","r",stdin);
    scanf("%lld",&t);
    while(t--){
        scanf("%lld",&n);
        ll ans=0,sum=0,maxx=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++) a[i][j]=0;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            cin>>ch[i][j];
            if(ch[i][j]=='1') a[i][j]=1,sum+=1;
        }
        for(int i=1;i<=n;i++){
            maxx=0;
            for(int j=0;j<n;j++){
                ll x=(i+j)%n==0?n:(i+j)%n;
                if(a[j+1][x]==1) maxx++;
            }
            ans=max(maxx,ans);
        }
        printf("%lld\n",sum+n-2*ans);
    }
	return 0;

 }

Promising String (hard version) 树状数组优化

观察一个字串可以得出一个结论,假设字串中加号的个数为ja,减号的个数为sub,减号能转化成加号的个数为add,则sub-2*add==add+ja;转化一下也就是要满足(sub-ja)%3==0&&(sub-ja)/3<=add;也就是说减号一定会大于等于加号,那我们设加号为-1,减号为1,那字串要满足的条件就是

sum[i]-sum[j]>=0,(sum[i]-sum[j])%3==0,也就是sum[i]>=sum[j];那把sum存入树状数组里,每次查i的时候只要看看有多少小于他的数就可以了,但是要设三个树状数组,因为mod3会有三种情况0,1,2只有当sum[i],sum[j]同余的时候才可以满足(sum[i]-sum[j])%3==0;另外树状数组不会有负数,找个加上最小负数的相反数加一就可以了,一开始入树状数组的时候一定要把0(或者是最小负数的相反数加一,也就是sum[0])先入进去,因为前缀和也是要考虑sum[0]的呀,比如求从1到i的子串,就需要sum[i]-sum[0];

​​​​​​Codeforces Round #780 (Div. 3) C D E F - 知乎 (zhihu.com)

#include <bits/stdc++.h>
#define ll long long
#define lowbit(i) ((i)&(-i))
using namespace std;
const ll mod=1000000007;
const ll inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a){return qpow(a,mod-2);}
ll t,n,sum[500005],a[300005];
string s;
struct shu{
    ll tr[500005];
    void add(ll x,ll y){
        for(int i=x;i<=500005;i+=lowbit(i))
            tr[i]+=y;
    }
    ll ask(ll x){
        ll res=0;
        for(int i=x;i;i-=lowbit(i))
            res+=tr[i];
        return res;
    }
    void init(ll ca){
        for(int i=1;i<=ca;i++) tr[i]=0;
    }
}tree[3];
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%lld",&t);
    while(t--){
        scanf("%lld",&n);
        cin>>s;
        s="0"+s;
        ll mi=0;
        for(int i=0;i<=n;i++) sum[i]=0;
        for(int i=1;i<=n;i++){
        if(s[i]=='+') sum[i]=sum[i-1]-1;
        else sum[i]=sum[i-1]+1;
        mi=min(mi,sum[i]);
        }
        mi=-mi+1;
        for(int i=0;i<=n;i++) sum[i]+=mi;
        for(int i=0;i<3;i++) tree[i].init(n+mi);
        ll ans=0;
        for(int i=0;i<=n;i++){//不加0的话就会漏掉从1开始的字符串的情况
            ll m=sum[i]%3;
            ans+=tree[m].ask(sum[i]);
            tree[m].add(sum[i],1);
        }
        printf("%lld\n",ans);
    }
	return 0;
 
 }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

killer_queen4804

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

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

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

打赏作者

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

抵扣说明:

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

余额充值