2019 EC-決勝ICPC

2019 ICPC EC-決勝再生


質問の意味:

N M、N * mがグリッドを表し
、このラインの中点が格子点が問題に適合することが意図されている場合、必要に応じてグリッド上の点を接続します。
どのように多くのそのような行を確認して下さい(すなわち、グリッドの終点で、格子点が中間点であり、線の長さが0ではない)
データ範囲:N、M <= 1E3

アイデア:

中間点に列挙位置。

コード:

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
    int n,m;
    cin>>n>>m;
    n++,m++;
    int ans=0;
    for(int i=1;i<=n;i++){//枚举中点
        for(int j=1;j<=m;j++){
            int a=min(i,n-i+1);
            int b=min(j,m-j+1);
            ans+=(a-1)*(b-1)*2+(a-1)+(b-1);
        }
    }
    cout<<ans<<endl;
    return 0;
}

C.Dirichletのk番目のルート(

コンボリューションの問題、自由アップ


E.Flow

質問の意味:

与えられたNノードは、重み付き無向グラフの辺をmです。前記N個の独立したパスの数、パスとノードの数が同じ(同じ経路長)に始端を有しています。各側は、右側を持っています。
一つの操作は片側プラス1、マイナス1別の1つの右側の右端を行うことができます。Qは、最大合計流量操作の最後に開始点が最小回数を必要とすることができます。
データ範囲:N <= 1E5、M < = 2E5、 エッジ重み<= 1E9

アイデア:

パスの長さが同じだからです。すべての重みは、一方の鎖上のエッジに蓄積されていると仮定し、それが導入され、右側の最大流量= /(鎖長)は、最後のその最大流量であることができます。
各鎖の右側はソートされ、次いで、積層、各層が算出され、右側れます。
各層および最大流量の右側には、我々は操作の数を算出することができるように、より少ない完了まで最大流量よりも、以上でなければならないので、最大流量を得るため。

コード:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e5+5;
int head[maxm],nt[maxm<<2],to[maxm<<2],w[maxm<<2],tot;
vector<int>temp;
int flow[maxm];
int n,m;
void add(int x,int y,int z){
    tot++;nt[tot]=head[x];head[x]=tot;to[tot]=y;w[tot]=z;
}
void dfs(int x,int fa){
    if(x==n)return ;
    for(int i=head[x];i;i=nt[i]){
        int v=to[i];
        if(v==fa)continue;
        temp.push_back(w[i]);
        dfs(v,x);
    }
}
signed main(){
    cin>>n>>m;
    int sum=0;
    for(int i=1;i<=m;i++){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
        sum+=c;
    }
    int elen=0;//路径长度
    for(int i=head[1];i;i=nt[i]){
        temp.clear();
        temp.push_back(w[i]);
        dfs(to[i],1);
        sort(temp.begin(),temp.end());//排序
        if(!elen)elen=temp.size();
        for(int i=0;i<elen;i++){//分层求和
            flow[i+1]+=temp[i];
        }
    }
    int maxflow=sum/elen;
    int ans=0;
    for(int i=1;i<=elen;i++){
        if(flow[i]<maxflow){
            ans+=maxflow-flow[i];
        }
    }
    cout<<ans<<endl;
    return 0;
}

H.King

質問の意味:

アレイと素数pの長さnは
王のシーケンスSの定義、シーケンスs満たすS(I-1)* Q%P = S(I)、( ダイセンスで等比級数)
今配列中のあなた曲から、配列が配列王であり、最大長は以下N / 2 -1出力を超える場合、Qは、数値の最大長さです。
データ範囲:N <= 2E5、p < = 1E9 + 7、 pは素数であることを保証するために

アイデア:

この問題の重要な点は、N / 2、(実際に各条件を被験者が無視できない!)ということである
少なくともN / 2の長さがあるため、シーケンス番号はそれほど一般的比こと、少なくとも2つの隣接する又は1によって分離さを有していなければならないのでそれは確かに隣接または分離しなければなりません
の数の一般的な比の(I)から(i)および(I-2)〜(I-1)を保存することができるすべてのマップによって
特定明らかに共通の比Qの発生をそれよりも大きく、または数に等しくなります

チェック数をn最大取ると思われるものの/ 8(長い時間をプッシュするためのnも/ 6は、どのように番号を知らない)よりも大きく、

コード:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxm=2e5+5;
unordered_map<int,int>mark;
int inv[maxm];
int a[maxm];
int n,p;
int ppow(int a,int b,int mod){
    int ans=1%mod;
    while(b){
        if(b&1)ans=(ll)ans*a%mod;
        a=(ll)a*a%mod;
        b>>=1;
    }
    return ans;
}
int cal(int q){
    unordered_map<int,int>dp;
    int ans=0;
    for(int i=n;i>=1;i--){
        dp[a[i]]=dp[(ll)a[i]*q%p]+1;
        ans=max(ans,dp[a[i]]);
    }
    return ans;
}
signed main(){
    int T;
    cin>>T;
    while(T--){
        unordered_map<int,int>t;
        mark=t;
        scanf("%d%d",&n,&p);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            inv[i]=ppow(a[i],p-2,p);
        }
        for(int i=2;i<=n;i++){
            int q=(ll)a[i]*inv[i-1]%p;
            mark[q]++;
        }
        for(int i=3;i<=n;i++){
            int q=(ll)a[i]*inv[i-2]%p;
            mark[q]++;
        }
        int ans=0;
        for(auto i:mark){
            if(i.second>=n/8){
                ans=max(ans,cal(i.first));
            }
        }
        if(ans*2<n)ans=-1;
        printf("%d\n",ans);
    }
    return 0;
}

M.Value

質問の意味:

長さnの配列aとbに
各位置iについては、Iを選択した場合、その後、合計スコアは、(i)を追加し、あるいはオプションです。
あなたはiとj、およびI、J> = 2、およびIを選択した場合、K = J(K> = 2)は、その後、あなたはB(j)を減算する必要があり、より多くの私は、この条件を満たしている場合には、B(j)の意志をこれは、いくつかの回を差し引かれます。
今、あなたは、この最大スコアの最終合計スコアの最大出力そのオプションを見つけたいです。
データ範囲:N <= 1e5,1 <= A (I)、B(I)<= 1E9

アイデア:

(1)義務、彼は他の数字には影響しませんので。
簡単には、8 = 2であるため、例えば、図8及び図9は、互いに影響を及ぼさない、お互いに影響を与えない対数の異なるベースを参照する。3、= 3 9 2
そののみN 1e5,2を発見した。17そう塩基数、最大のグループによってパケット場合、1E5よりも大きいですグループ2のベースであり、数は17以上、他の小さなグループの数ではありません。
ベース・パケットを押すことが可能である、とバイナリオプションのセットごとに最大を取る列挙、蓄積が答えです。

コード:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e5+5;
vector<int>g[maxm];
int cnt=0;
int mark[maxm];
int a[maxm];
int b[maxm];
int solve(int x){//计算第x组的最大答案
    int len=g[x].size();
    int ans=0;
    for(int i=0;i<(1<<len);i++){
        for(int j=0;j<len;j++)mark[g[x][j]]=0;//清空标记
        int temp=0;
        for(int j=0;j<len;j++){
            if(i>>j&1){
                temp+=a[g[x][j]];
                temp-=mark[g[x][j]]*b[g[x][j]];
                for(int k=g[x][j]*g[x][j];k<=g[x][len-1];k*=g[x][j]){
                    mark[k]++;
                }
            }
        }
        ans=max(ans,temp);
    }
    return ans;
}
signed main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)cin>>b[i];
    for(int i=2;i<=n;i++){//按底数分组
        if(mark[i])continue;
        cnt++;
        for(int j=i;j<=n;j*=i){
            mark[j]=1;
            g[cnt].push_back(j);
        }
    }
    int ans=a[1];//a[1]必选,因为对后续无影响
    for(int i=1;i<=cnt;i++){//对每一组二进制枚举
        ans+=solve(i);
    }
    cout<<ans<<endl;
    return 0;
}

公開された430元の記事 ウォン称賛36 ビュー20000 +

おすすめ

転載: blog.csdn.net/weixin_44178736/article/details/104741866