説明の貪欲テーマ別がんHBXシリーズ
最大GCDの
質問の意味は:今、正の整数nを与えられました。あなたは厳密に増加k個の正の整数のA1、A2、...、AKを見つけ、nおよびできるだけ大きくその最大公約数に等しい自分を満たしている必要があります。可能でない場合は、出力を喜ば-1。\(1個の\当量のN、K
\当量10 ^ {10} \) 溶液:Nのすべての要因が見つけるための後、最大X因子満足を見出す\(X * \ FRAC {k個 *(K + 1)} {2 } \当量のn \)ことができます。配列である(1 * X 2 * \ X、...、(K-1)* X、NX * \ FRAC {K×(K-1)} {2} \)
判定が長いロングバーストことに注意してください!
複雑さ:\(O(\ sqrtのN-)\)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,k,tmp,tp,sum,fac[5005];
int faccnt;
inline bool check(ll x)
{
return x<=(2*n/k)/(k+1);//!!!
}
int main()
{
scanf("%lld%lld",&n,&k);
sum=n;
if(!check(1))
{
puts("-1");
return 0;
}
for(register ll i=1;i*i<=n;++i)
{
if(n%i) continue;
if(check(i)) tmp=max(tmp,i);
if(check(n/i)) tmp=max(tmp,n/i);
}
for(int i=1;i<k;++i)
printf("%lld ",1ll*i*tmp),sum-=i*tmp;
printf("%lld\n",sum);
return 0;
}
Bアーサー壁
質問の意味は:「 『』 『』。」、このようなブロックユニコムに『*』や記号の2種類の最小要件『*』のn×m個の行列を与えます長方形。これは、少なくともいくつかを変更する必要があります必要があり、「*。」\(1個の\当量のN、Mの
\の当量2000 \) ソリューション:2 * 2のブロックは、唯一の"*" "*"アウトに変更置く場合。BFSは、することができます。
複雑さ:\(O(^ N-2)\)
#include<bits/stdc++.h>
using namespace std;
#define maxn 2005
int G[maxn][maxn],b[5];
char s[maxn][maxn];
int n,m;
struct Node
{
int x,y;
Node(){}
Node(int a,int b):x(a),y(b){}
};
queue<Node> q;
inline void work(int x,int y)
{
if(G[x][y])
G[x][y]=0,q.push(Node(x,y));
}
inline void bfs()
{
while(!q.empty())
{
int x=q.front().x,y=q.front().y;
q.pop();
b[1]=b[2]=b[3]=b[4]=0;
if(x!=1&&y!=1) b[1]=G[x-1][y-1]+G[x-1][y]+G[x][y-1];
if(x!=1&&y!=m) b[2]=G[x-1][y]+G[x-1][y+1]+G[x][y+1];
if(x!=n&&y!=1) b[3]=G[x][y-1]+G[x+1][y-1]+G[x+1][y];
if(x!=n&&y!=m) b[4]=G[x][y+1]+G[x+1][y]+G[x+1][y+1];
if(b[1]==1)
work(x-1,y-1),work(x-1,y),work(x,y-1);
if(b[2]==1)
work(x-1,y),work(x-1,y+1),work(x,y+1);
if(b[3]==1)
work(x,y-1),work(x+1,y-1),work(x+1,y);
if(b[4]==1)
work(x,y+1),work(x+1,y),work(x+1,y+1);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
scanf("%s",s[i]+1);
for(int j=1;j<=m;++j)
{
if(s[i][j]=='.') q.push(Node(i,j));
else G[i][j]=1;
}
}
bfs();
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
if(G[i][j]==1) cout<<"*";
else cout<<".";
}
puts(" ");
}
return 0;
}
C学生の復讐
の質問の意味は:1日あたり大量のトランザクションを処理するための会長を持っているが、学生はまだ彼と非常にうんざりしています。n個のタスクがあり、学生は、n-kの残りの部分は完全ではありません完了するために、kの会長に選出され、P]を選択します。
会長は、タスクの毛白完了します\を(A_ {I} \) 、それは学生の不満が増大し完了しません\(B_ {I}を\) 。社長であろう\(\和{B_ {I }} \) これに基づいて、できるだけ小さいこと\(\和{A_ {I }} できるだけ小さい\) 。しかし、作りたい学生\(\ {合計A_ {I }} \) に基づき、できるだけ大きなを、\(\ {合計B_ {I }} \) できるだけ大きく。
P目指す学生たちは1つがあなたが選び、kの会長と思われる選択します。
まず出力と生徒の出力がPKヶ月の社長に投票した後、kの出力会長を選択しないことを選択しました。番号順に出力します。
\(1 \当量のK \当量
のp \当量のn個の\当量10 ^ 5,1 \当量のA_ {I}、B_ {I} \当量10 ^ 9 \) 溶液:pは議長に結合し、タスク与えられた場合プレスbは、その後、昇順で並べ替え降順で解決しました。だから、抗プッシュプレス、その後PK降順に選挙の前に、確かではない昇順B。したがって、最初のn個のPKを除去する前に(マークが選択することができません)。
第二に、我々はKとPK B-最大の最大値を選択します。そのkの唯一の代表取締役社長を補うために、最初のk bのbの値がなければならないPKの背面の値よりも大きいです。コードの具体的な実現を見て。
複雑さ:\(O(N \ N-ログ)\)
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 100005
struct Things
{
int a,b,id,state;
}thi[maxn];
int n,p,k,vis[maxn],cnt,num;
inline bool cmp1(Things x1,Things x2)
{
if(x1.b!=x2.b) return x1.b<x2.b;
if(x1.a!=x2.a) return x1.a>x2.a;
return x1.state<x2.state;
}
inline bool cmp2(Things x1,Things x2)
{
if(x1.a!=x2.a) return x1.a>x2.a;
return x1.b>x2.b;
}
int main()
{
scanf("%d%d%d",&n,&p,&k);
for(int i=1;i<=n;++i)
scanf("%d%d",&thi[i].a,&thi[i].b),thi[i].id=i;
sort(thi+1,thi+n+1,cmp1);
for(int i=1;i<=p-k;++i) thi[i].state=1;//扔后面去
sort(thi+1,thi+n+1,cmp2);
for(int i=1;cnt<k;++i)
if(!thi[i].state)
{
++cnt;
vis[thi[i].id]=1;
thi[i].state=2;//同上
printf("%d ",thi[i].id);
}
sort(thi+1,thi+n+1,cmp1);
cnt=0;
for(int i=n;num<p-k;--i)//从后往前扫
{
if(cnt>=k)
{
++num;
printf("%d ",thi[i].id);
}
if(vis[thi[i].id]) ++cnt;
}
return 0;
}
Dボール着色
問題の意味:2つの数の数であるように数がn個のスタックとl rのスタックに置かれます。探している\(MIN((R_ {分間{最大}} -R_)*(L_ {分間{最大}} -L_))\)
\(1 \ n型のLeq \のLeq 200000,1 \のLeq NUM \ ^ 10 9のLeqを\)
質問ソリューション:みましょう\(最小、最大\)が全体の最大値(最小値)です。
1)すべての最小ヒープの小さな数に投げ込まれ、最大ヒープの多数に投入:Minは、Maxは同じヒープでない場合。
2)同じでスタック場合:我々は要求\(MIN(R_ {分間{maxは}} -R_)\) 。小さな値のx個、大きい値のY番号をしましょう。Xで並べ替え。X、Yのやり取りが続き、答えを更新します。
注:最小場合、max)は2をスキップ同じ数であってもよいです。
複雑さ:\(O(N \ N-ログ)\)
#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
struct Card
{
int x,y;
inline friend bool operator < (Card a,Card b)
{
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
}card[maxn];
int Rmax,Rmin,Bmax,Bmin,maxpos,minpos;
int main()
{
int n;
scanf("%d",&n);
if(n==1)
{
puts("0");
return 0;
}
for(int i=1;i<=n;++i)
{
scanf("%d%d",&card[i].x,&card[i].y);
if(card[i].x>card[i].y) swap(card[i].x,card[i].y);
}
sort(card+1,card+n+1);
int maxy=card[1].y,minx=card[1].x;
for(int i=1;i<=n;++i)
{
if(card[i].x<=minx&&card[i].y>=maxy)
{
maxpos=minpos=i;
minx=card[i].x,maxy=card[i].y;
}
else if(card[i].x<minx)
{
minpos=i;
minx=card[i].x;
}
else if(card[i].y>maxy)
{
maxpos=i;
maxy=card[i].y;
}
}
Rmax=maxy,Bmin=minx;//全局最大最小
Rmin=card[minpos].y,Bmax=card[maxpos].x;
for(int i=1;i<=n;++i)
{
Rmin=min(Rmin,card[i].y);
Bmax=max(Bmax,card[i].x);
}
long long ans=1ll*(Rmax-Rmin)*(Bmax-Bmin);//第一种情况
if(maxpos!=minpos)//第二种情况
{
Bmax=maxy,Bmin=minx;
Rmax=max(card[n].x,card[1].y);
int premin=card[1].y;
Rmin=min(card[1].y,card[2].x);
int tmp=Rmax-Rmin;
for(int i=2;i<n;++i)
{
Rmax=max(card[i].y,Rmax);
Rmin=min(min(card[i].y,premin),card[i+1].x);
premin=min(premin,card[i].y);
if(Rmax-Rmin<tmp) tmp=Rmax-Rmin;
}
ans=min(ans,1ll*tmp*(Bmax-Bmin));
}
printf("%lld\n",ans);
return 0;
}
Eアントマンの
タイトル意味:n個の点と、各点はX、A、B、C、有する D 5つのプロパティを。iからjへの定義された距離である
} {始める\ケース
MID X_ {J} -x_ {I} \ \ + MID B_ C_ {I} + {J}、&X_ {I}> {J} X_ \ NEWLINE
\ X_ MID {J} \ + MID + D_ {I} A_ {J} -x_ {I}、&X_ {J}> {I} X_
\ケース}終了{
所与の開始点と終了点、各点は一度だけ後シーク最短。
\(n個の\当量5000,1 \当量
X、A、B、C、D \当量10 ^ 9 \) 保証X、A、B、C、 Dが厳密に単調増加しています。
解決策:リンクリストを維持するために、インターバル中に直接挿入します。
複雑さ:\(O(^ N-2)\)
#include<bits/stdc++.h>
using namespace std;
struct Point
{
long long x,a,b,c,d;
}poi[5005];
int n,s,e,nex[5005],tmppos;
long long ans,cost,tmpcost;
inline long long dist(int x,int y)
{
Point a=poi[x],b=poi[y];
if(b.x<a.x) return a.x-b.x+a.c+b.b;
return b.x-a.x+a.d+b.a;
}
int main()
{
scanf("%d%d%d",&n,&s,&e);
for(int i=1;i<=n;++i) scanf("%lld",&poi[i].x);
for(int i=1;i<=n;++i) scanf("%lld",&poi[i].a);
for(int i=1;i<=n;++i) scanf("%lld",&poi[i].b);
for(int i=1;i<=n;++i) scanf("%lld",&poi[i].c);
for(int i=1;i<=n;++i) scanf("%lld",&poi[i].d);
nex[s]=e;
ans+=dist(s,e);
for(int i=1;i<=n;++i)
{
if(i==s||i==e) continue;
cost=1e18;
for(int j=s;j!=e;j=nex[j])
{
tmpcost=dist(j,i)+dist(i,nex[j])-dist(j,nex[j]);
if(cost>tmpcost)
{
cost=tmpcost;
tmppos=j;
}
}
ans+=cost;
nex[i]=nex[tmppos];
nex[tmppos]=i;
}
printf("%lld\n",ans);
return 0;
}
上記は試験問題です。
F新年雪だるま
の質問の意味:指定された\(R_ {I} \) 、どのように多くのトリプルまでの互いに異なる要素を求めています。\(1 \当量のn \の当量
^ 5 * 10、R_ {I} \当量10 ^ 6 \) 溶液:各残りの3つまで来ます。
複雑さ:\(O(N \ N-ログ)\)
#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
int n,cnt,tmp[maxn],anscnt,t1,t2,t3;
struct Ball
{
int size,num;
inline friend bool operator < (Ball a,Ball b)
{
if(a.num==b.num) return a.size<b.size;
return a.num<b.num;
}
}ball[maxn],tmpa,tmpb,tmpc;
struct Ans
{
int t1,t2,t3;
}ans[maxn];
priority_queue<Ball> q;
inline void func(Ball x)
{
if(x.num>1) q.push((Ball){x.size,--x.num});
else --cnt;
}
inline void work()
{
tmpa=q.top(),q.pop();
tmpb=q.top(),q.pop();
tmpc=q.top(),q.pop();
t1=tmpa.size,t2=tmpb.size,t3=tmpc.size;
if(t1<t2) swap(t1,t2);
if(t1<t3) swap(t1,t3);
if(t2<t3) swap(t2,t3);
ans[++anscnt]=(Ans){t1,t2,t3};
func(tmpa),func(tmpb),func(tmpc);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&tmp[i]);
sort(tmp+1,tmp+n+1);
for(int i=1;i<=n;++i)
{
if(tmp[i]!=tmp[i-1])
ball[++cnt].size=tmp[i],ball[cnt].num=1;
else ++ball[cnt].num;
}
for(int i=1;i<=cnt;++i) q.push(ball[i]);
while(cnt>=3)
work();
printf("%d\n",anscnt);
for(int i=1;i<=anscnt;++i)
printf("%d %d %d\n",ans[i].t1,ans[i].t2,ans[i].t3);
return 0;
}
Gサウスパークモントリオールスタック光フロック
イタリアこと:正の整数のシーケンスについて\(A_ {I} \)及び(B_ {I} \)\、及びB配列は増加厳密に単調ではなく、そのよう\(MAX(\ミッドA_ { I} \中間-b_ {I} )\) はできるだけ小さいです。与えられた\(A_ {I} \) 。
\(N \の当量5×10
^ 6 \) 解決方法:ドロー\(A_ {I} \)線グラフの答えは、二つの切り上げの最大逆添加の差として求めることができます。もちろん、半分は(私は知りませんが、ログも速く持っていないよりも、理由をログで実行)することができます。
複雑さ:\(O(N)\)
#include<bits/stdc++.h>
using namespace std;
long long a[5000005],sa,sb,sc,sd,mod;
int n;
inline long long mul(long long a,long long b)
{
return a*b%mod;
}
inline long long func(long long x)
{
return (mul(sa,mul(x,mul(x,x)))+mul(sb,mul(x,x))+mul(sc,x)+sd)%mod;
}
inline void pre()//生成数据的
{
scanf("%d%lld%lld%lld%lld%lld%lld",&n,&sa,&sb,&sc,&sd,&a[1],&mod);
for(int i=2;i<=n;++i)
a[i]=(func(a[i-1])+func(a[i-2]))%mod;
}
int main()
{
pre();
long long ans=-1e18,maxn=-1e18;
for(int i=1;i<=n;++i)
{
if(maxn>a[i]) ans=max(ans,(maxn-a[i]+1)>>1);
else maxn=a[i];
}
printf("%lld\n",ans);
return 0;
}
Hパベル三角形
イタリア:そこスティックNしている、私の長さ\(^ {I-2} 1 \。) 。各スティックの所定数\(A_ {I}が\) 、三角形の最大数を構成することができます。
\(1 \当量のn \の当量
^ 5 3 * 10、A_ {I} \当量10 ^ 9 \) 溶液:スイープを前後、二等辺優先グループは、等辺する複数のグループが存在します。
複雑さ:\(O(N)\)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll a[300005];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
ll ans=a[1]/3,num;
a[1]%=3;
ll res=a[1];
for(int i=2;i<=n;++i)
{
num=min(res,a[i]/2);
res-=num;
ans+=num;
a[i]-=num*2;
ans+=a[i]/3;
res+=a[i]%3;
}
printf("%lld",ans);
return 0;
}
I Nauuoとカード
の質問の意味:あなたは持っているかのn枚のカードは、n個のカードのデッキは、0張カードがn個あり、nは番号カード(1からnまで)。一つの操作はデッキに彼のカードの底部と手を得るために、カードの最上部デッキとして定義され、カードのデッキになることができます操作の最小数を使用する必要があり(1 \シムのn \)\のをシーケンスを命じました。
溶液:ナンバープレートが手に直接コールする最初のものを受信した場合。各カードの位置\(POS_ {I} \)を考慮\((POS [I] + +1)+(Ni)の\) 、すなわちカードを果たし増加を折り畳みます。最大を取ることができます。パイル内のナンバープレートは、それから形成されているかどうかを確認した場合\(POSの[1] \ N-SIM \)、\ (1 \ SIM K \)配列。このようなシーケンスは明らかに優れている場合。
複雑さ:\(O(N)\)
#include<cstdio>
using namespace std;
#define maxn 200005
int a[maxn], b[maxn], pos[maxn], ans;
inline int max(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int n, i;
scanf("%d", &n);
for (i = 1; i <= n; ++i) scanf("%d", &a[i]), pos[a[i]] = 0;
for (i = 1; i <= n; ++i) scanf("%d", &b[i]), pos[b[i]] = i;
for (i = 1; i <= n; ++i) ans = max(ans, pos[i] - i + n + 1);
if (pos[1])
{
for (i = 2; pos[i] == pos[1] + i - 1; ++i);
if (pos[i - 1] == n)
{
int j;
for (j = i; j <= n && pos[j] <= j - i; ++j);
if (j > n)
{
printf("%d\n", n + 1 - i);
return 0;
}
}
}
printf("%d\n", ans);
return 0;
}
Jマッチポイント
列の所定の数:そのイタリア\(X_ {I} \) 、場合(MID \ \ MID X_ {J} -x_ Z \のLeq \ {I})\、と呼ばれる\(X_ {I}、X_を{J} \)一致させることができます。
どのように多くのグループに対にシーク。\(2 \当量のn \の当量
2×10 ^ 5,1 \当量Z、X_ {I} \ leq10 ^ 9 \) 溶液:2分。ミッドフロントとリアミッド順次一つに一致します。
複雑さ:\(O(N \ N-ログ)\)
#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
int n,z,pos[maxn];
inline bool check(int x)
{
for(int i=1;i<=x;++i)
if(abs(pos[i]-pos[n-x+i])<z) return false;
return true;
}
int main()
{
scanf("%d%d",&n,&z);
for(int i=1;i<=n;++i) scanf("%d",&pos[i]);
sort(pos+1,pos+n+1);
int l=0,r=(n>>1),mid,ans;
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
printf("%d\n",ans);
return 0;
}
Kアルテムとアレイ
の質問の意味:指定されたシーケンス\(A_ {I} \) 、番号のそれぞれ左側及び右側の数を削除することによって、ポイントの最小数を得ることができます。最大の割合を求めて。\(1 \当量のn \の当量
5×10 ^ 5,1 \当量のA_ {I} \当量10 ^ 6 \) 溶液:最後の二つを削除することによって選別に加えて、大規模な第一中間小辺(単調スタック)を削除外。
複雑さ:\(O(N \ N-ログ)\)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll a[600005], ans;
int n, top, x;
int main()
{
scanf("%d", &n);
while (n--)
{
scanf("%d", &x);
while (top && a[top] <= x && a[top] <= a[top - 1])
ans += min(a[--top], x * 1ll);
a[++top] = x;
}
sort(a + 1, a + top + 1);
for (int i = 1; i <= top - 2; ++i) ans += a[i];
printf("%lld", ans);
return 0;
}
L北京ガード
イタリア:nは個々のフォームがリング。一人一人が贈り物を受け取った彼は、両側の人が同じであることはできません。Q.あなたが最も必要とするどのように多くの贈り物。誰もが必要とする\(A_ {I} \)の贈り物を。\(1 \当量のn \の当量
10 ^ 5 \) 溶液:nは偶数直接採取された場合\(MAX(A_ {I} + A_ {I + 1})\) することができます。それ以外の場合は半分。セット\(A_ {1} \)分割線についてです。私が奇数の場合、左または取る権利を取るようにしてみてください。最後に、n番目の左側に引き継ぐかどうかを見てください。
直接出力すること、N = 1に注意してください。
複雑さ:\(O(N \ N-ログ)\)
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 100005
int n, a[maxn], cl[maxn], cr[maxn];
long long l, r;
inline bool check(long long x)
{
cl[1] = a[1];
for (int i = 2; i <= n; ++i)
{
if (i & 1)
{
cr[i] = min(0ll + a[i], x - a[1] - cr[i - 1]);
cl[i] = a[i] - cr[i];
}
else
{
cl[i] = min(a[i], a[1] - cl[i - 1]);
cr[i] = a[i] - cl[i];
}
}
return !cl[n];
}
int main()
{
while (scanf("%d", &n) && n)
{
l = r = 0;
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), r += a[i];
if (n == 1)
{
printf("%d\n", a[1]);
continue;
}
a[n + 1] = a[1];
for (int i = 1; i <= n; ++i) l = max(l, 0ll + a[i] + a[i + 1]);
if (!(n & 1))
{
printf("%lld\n", l);
continue;
}
while (l <= r)
{
long long mid = (l + r) >> 1;
if (check(mid)) r = mid - 1;
else l = mid + 1;
}
printf("%lld\n", l);
}
return 0;
}
Mテーブルの移動
の質問の意味を:廊下があり、することができます唯一のテーブルによる。10分であることを任意の二つの部屋の間でテーブルを移動します。与えられたNテーブルと、それらを移動する分の最大数を求めるために、開始点と終了。同じ時間には、複数のテーブルを移動することができます。ルーム400、\(N- \のLeq 200です\)
ソリューション:移動部10と、最終的なテイク最大に追加。
複雑さ:\(O(^ N-2)\)
#include<bits/stdc++.h>
using namespace std;
int cnt[405];
int main()
{
int t, n, st, ed, ans;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
memset(cnt, 0, sizeof(cnt));
while (n--)
{
scanf("%d%d", &st, &ed);
if (st > ed) swap(st, ed);
if (!(st & 1)) --st;
if (ed & 1) ++ed;
for (int i = st; i <= ed; ++i) cnt[i] += 10;
}
ans = 0;
for (int i = 1; i <= 400; ++i) ans = max(ans, cnt[i]);
printf("%d\n", ans);
}
return 0;
}