Ji Garke 2020ブルーブリッジカップ地方競技グループBシミュレーション競技(5)Eセクションdp H Pei Shu J dp AJウェイトラインセグメントツリー

タイトルリンク

筆記試験のため。だから、プレイには2時間しかかからず、少し早く、多くの詳細は急いで渡されず、検査もありませんでした。

揚げステーキ

 

方法:すべての面の数はsum = 2 * nであり、次にsum /(2 * k)です。

ans = max(10、n / k)パンケーキが1つしかない場合は、10分間揚げられるため、最小は10分です。

Eカードゲーム

間隔dp +記憶された検索

間隔でlからrのとき、dp [l] [r]をニンニクの頭のジュンからHua Yemeiを差し引いたものとする

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e2+10;
ll dp[N][N],a[N];

int vis[N][N],n;
ll dfs(int l,int r,int ty)
{
     if(l>r) return 0;
     if(vis[l][r]) return dp[l][r];
     vis[l][r]=1;
     ll &ans=dp[l][r];
     if(ty==0){
        ans=max(dfs(l+1,r,1)+a[l],dfs(l,r-1,1)+a[r]);
     }
     else{
        if(a[l]>=a[r]) ans=dfs(l+1,r,0)-a[l];
        else ans=dfs(l,r-1,0)-a[r];
     }
     return dp[l][r];

}
int main()
{
     cin>>n;
     for(int i=1;i<=n;++i) cin>>a[i];
     ll ans=dfs(1,n,0);
     cout<<ans<<endl;
     return 0;
}
/*
4
3 2 10 4
ans:7
*/

H-twoアレイ

実践:ペイシュウの定理+導出

Pei Shuの定理により、a配列の隣接する差は、方程式変換を実行するためにb配列を必要とすることがわかります。

x1 * b [1] + x2 * b [2] ...... xn * b [n] == a [i + 1] -a [i] 

 

また、x1 * b [1] + x2 * b [2] ...... xn * b [n] = k * gcd(x1、x2、x3 ... xn)には解があります

a配列の最後の数がxであると仮定  

dとする:d = xa [i]

つまり、x1 * b [1] + x2 * b [2] ...... xn * b [n] = d余り0またはx1 * b [1] + x2 * b [2] .... ..xn * b [n] = d1 Yu mod ==> d1 + mod = d

 

したがって、すべての差を埋める必要があります。すべての差は、gcdの係数(x1、x2、x3 ... xn)と同じ余りです。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi 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;}
const int N=1e5+10;
int n,m;
ll a[N],b[N];
int main()
{
    int _;cin>>_;while(_--)
    {
        scanf("%d%d",&n,&m);
        rep(i,1,n) scanf("%lld",&a[i]);
        rep(i,1,m) scanf("%lld",&b[i]);
        if(n==1){puts("Yes");continue;}

        
        ll d=b[1];
        rep(i,2,m) d=gcd(d,b[i]);
        sort(a+1,a+1+n);
        
        
        int flag=1;
        ll res=(a[2]-a[1])%d;
        for(int i=1;i<n&&flag;++i){
            ll t=a[i+1]-a[i];
            if(t%d!=res) flag=0;
        }

        if(flag) puts("Yes");
        else puts("No");
    }
}
/*
4
2 6 10 12
2 3 4 5
*/

I関数の総和

トピック:

練習:

コード:

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef unsigned long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e5+10;
const ll mod=998244353;
ll a[N],b[N],c[N];
int n;

bool cmp(ll x,ll y)
{
    return x>y;
}
void add(ll &x,ll y)
{
    x=(x+y)%mod;
}
int main()
{
    scanf("%d",&n);
    rep(i,1,n) {
        cin>>a[i];
        a[i]=1ll*i*(n-i+1)*a[i];
    }
    rep(i,1,n)cin>>b[i];


    sort(a+1,a+1+n);
    sort(b+1,b+1+n,cmp);

    ll ans=0;
    rep(i,1,n) {
        ll x=a[i]%mod*b[i]%mod;
        add(ans,x);
    }
    
    cout<<ans<<endl;
    return 0;
}

Jシーケンス分割

トピック:

公式ソリューション:

ここでのサブシーケンスでは、添え字が連続して一緒にグループ化されている必要があることに注意してください。添え字は不連続であり、貪欲に書き込みますwa

添え字が連続している場合、それは古典的なdpです。接頭辞の合計と間隔の最小値を維持できます。

dp [i]を最初のi要素に割り当てられた最小の重みの合計とします。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi 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;}
const int N=1e5+10;
ll a[N],dp[N],mi[4*N],sum[N];
int n,c;
void build(int id,int l,int r)
{
    if(l==r) {
        mi[id]=a[l];
        return ;
    }
    int mid=l+r>>1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    mi[id]=min(mi[id<<1],mi[id<<1|1]);
}
ll qu(int id,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr) return mi[id];
    ll res=1e18;
    int mid=l+r>>1;
    if(ql<=mid) res=qu(id<<1,l,mid,ql,qr);
    if(qr>mid) res=min(res,qu(id<<1|1,mid+1,r,ql,qr));
    return res;
}
int main()
{
    cin>>n>>c;
    rep(i,1,n)
    {
        scanf("%lld",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    for(int i=1;i<c;++i) dp[i]=dp[i-1]+a[i];
    build(1,1,n);

    for(int i=c;i<=n;++i){
        dp[i]=min(dp[i-1]+a[i],dp[i-c]+sum[i]-sum[i-c]-qu(1,1,n,i-c+1,i));
    }
    cout<<dp[n]<<endl;
}
/*
12 10
1 1 10 10 10 10 10 10 9 10 10 10
*/

ちなみにグループAの質問を書きます。

グループA

E-GCD

トピック:

練習:古典的なオイラー関数

 

グループA Jすべて配置

トピック:

cf元のタイトル。

ブログリンク

元の質問リンクE質問

公式ソリューション:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=2e5+10;
int p[N],n;
ll a[N],sum[4*N],lazy[4*N],mi[4*N];
void pushdown(int id)
{
    if(lazy[id]){
        lazy[id<<1]+=lazy[id];
        lazy[id<<1|1]+=lazy[id];
        mi[id<<1]+=lazy[id];
        mi[id<<1|1]+=lazy[id];
        lazy[id]=0;
    }
}
void up(int id,int l,int r,int ql,int qr,ll val)
{
    if(ql<=l&&r<=qr){
        lazy[id]+=val;
        mi[id]+=val;
        return ;
    }
    pushdown(id);
    int mid=l+r>>1;
    if(ql<=mid) up(id<<1,l,mid,ql,qr,val);
    if(qr>mid) up(id<<1|1,mid+1,r,ql,qr,val);
    mi[id]=min(mi[id<<1],mi[id<<1|1]);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d",&p[i]);
    }
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
    }


    for(int i=1;i<n;++i){
        up(1,1,n,1,p[i],a[i]);
    }

    if(p[n]+1<=n)up(1,1,n,p[n]+1,n,a[n]);

    ll ans=min(a[1],a[n]);
    ans=min(ans,mi[1]);
    for(int i=n-1;i>1;--i){
        if(p[i]+1<=n) up(1,1,n,p[i]+1,n,a[i]);
        up(1,1,n,1,p[i],-a[i]);
        ans=min(ans,mi[1]);
    }
    printf("%lld\n",ans);
}

 

元の記事519件を公開 賞賛された69件 50,000件以上の表示

おすすめ

転載: blog.csdn.net/qq_41286356/article/details/105458581