\(2019 \)夏のブラシタイトルレコード\(2 \) (基本的なテーマのアルゴリズム)
\(~~ \するWCH)
\(BZOJストレンジハノイ〜の〜1958 ~~~タワーズ\) (ダイナミックプログラミング、再帰的)
効果の件名:
請う\(N \)プレートと\(4 \)のハノイの塔の塔。
\(Solotion:\)
- ハノイの塔の最初の三つの列を参照する必要がある:\([1-I] G [I] = 2 * Gの+ +1 \)
- その後、我々は3つの塔4つの塔の質問に変換します:フロント\(私は\)プレート第2タワー、残りの\(NI \) 3つの飯能第4の塔への移動、前者を\ (私は\)ハノイ塔第4の4つの塔によって移動します。
- (\ \ {[NI] G [I] + 2 * F} [N] = MIN_ {iがn <1基の\当量} F)
\(コード:\)
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define db double
#define rg register int
using namespace std;
int n=12;
int g[13],f[13];
inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar()))if(ch=='-')sign=1;
while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
if(sign)return -res; else return res;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
for(rg i=1;i<=n;++i) g[i]=2*g[i-1]+1;
for(rg i=1;i<=n;++i){
f[i]=1<<30;
for(rg j=0;j<i;++j)
f[i]=min(f[i],f[j]*2+g[i-j]);
}
for(rg i=1;i<=n;++i)
printf("%d\n",f[i]);
return 0;
}
$ BZOJ〜1218〜$レーザー爆弾(接頭辞と2次元)
\(Solotion:\)
- より明白と二次元のプレフィックス問題
- この問題は、多くの場合、少しカードで、もし一次元の接頭辞暴力的なターンとアウト時間
- 私たちは、自分自身のプレフィックスと各点の関係を見つける必要があります。
- \(S [I] [J] = S [I-1]〜[J] + S [I] [J-1] -s [I-1] [J-1] + [I] [J] \ )
\(コード:\)
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<queue>
#include<vector>
#include<map>
#include<set>
#define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int
using namespace std;
int n,m,ans,a,b,c;
int f[5003][5003];
inline int qr(){
char ch; //int sign=1;
while((ch=getchar())<'0'||ch>'9');
// if(ch=='-')sign=-1;
int res=ch^48;
while((ch=getchar())>='0'&&ch<='9')
res=res*10+(ch^48);
return res;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n=qr(),m=qr();
for(rg i=1;i<=n;++i){
a=qr()+1,b=qr()+1,c=qr();
f[a][b]=c;
}
for(rg i=1;i<=5001;++i)
for(rg j=1;j<=5001;++j)
f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
for(rg i=m;i<=5001;++i){
for(rg j=m;j<=5001;++j){
ans=max(ans,f[i][j]-f[i-m][j]-f[i][j-m]+f[i-m][j-m]);
}
}printf("%d\n",ans);
return 0;
}
\(POJ〜3263 ~~最も高い牛\) (接頭辞と貪欲)
\(Solotion:\)
- 私は、昔より興味深い接頭辞の一つと実践を行っています
- まず、私たちは貪欲牛の高さの時間マイナス1を考え、その後の減少の最小数を計算することができます
- 各牛の数を減らし、高さがあることを高さを低くするために、我々は彼らの家畜の真ん中にお互いを見ることができ、各牛のために決定されます
- だから我々は(a_iを\)\プラスワンで、\(\ B_i + 1) 、その後、マイナスのプレフィックスでとはそれぞれが牛を知ることができる回数を削減しよう
- その後、牛の二つの端点よりも短くなるように、すべての牛にこの問題を心配しないでください、すべてのセクションには、関係を含めなければならないが、交差していません
\(コード:\)
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int
using namespace std;
int n,m,h,q,a,b;
int s[10001];
bool use[10001][10001];
inline int qr(){
char ch;
while((ch=getchar())<'0'||ch>'9');
int res=ch^48;
while((ch=getchar())>='0'&&ch<='9')
res=res*10+(ch^48);
return res;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n=qr(),m=qr(),h=qr(),q=qr();
while(q--){
a=qr(),b=qr();
if(a>b)swap(a,b);
if(use[a][b])
continue;
use[a][b]=1;
--s[a+1];
++s[b];
}
for(rg i=1;i<=n;++i){
s[i]=s[i]+s[i-1];
printf("%d\n",h+s[i]);
}
return 0;
}
\(POJ〜1845〜Sumdiv \) (数および定理について)(パーティション)
効果の件名:
探している\(^ A B \)数は約和のすべてを
\(Solotion:\)
- 第1及び定理の数を知るために\((P_1 1 + 2 + ... + ^ + P_1 P_1のC_1と^ {})*(P_2 + 2 1 + ... + P_2 ^ + ^ {P_2のC_2})*。 ... *(1 + p_k + p_k ^ 2 + ... + p_k ^ {c_k})\)
- そして、この質問は良く行われ、ある\(^ A B \)すべてについてと方程式の数は、すべて作ることです\(C_I \)を乗じた\(B \)に
- そして、括弧内の何かが直接分割し、征服しよう
\(コード:\)
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define db double
#define rg register int
using namespace std;
const int mod=9901;
int n,m,ans;
inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar()))if(ch=='-')sign=1;
while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
if(sign)return -res; else return res;
}
inline int ksm(ll x,int y){
ll res=1;
while(y){
if(y&1)res=res*x%mod;
x=x*x%mod; y>>=1;
}return res;
}
inline int ask(int x,int y){
if(y==1)return x;
if(y&1) return ((ll)ask(x,y>>1)*(ksm(x,y>>1)+1)%mod+ksm(x,y)%mod)%mod;
else return (ll)ask(x,y>>1)*(ksm(x,y>>1)+1)%mod;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
while(~scanf("%d%d",&n,&m)){
if(m==0){puts("1");continue;}
ans=1;
for(rg i=2;i*i<=n;++i){
if(n%i)continue;
rg x=0; while(!(n%i))++x,n/=i;
ans=(ll)ans*(ask(i%mod,x*m)+1)%mod;
}if(n!=1)ans=(ll)ans*(ask(n%mod,m)+1)%mod;
printf("%d\n",ans);
}
return 0;
}
\(ベストPOJ〜2018 ~~~牛フェンス\) (二分答えは、新たな重みを構築)
個別の問題解決
\(POJ〜3889〜フラクタルストリーツ\) (アナログ)
個別の問題解決
\(Codeforces〜670C〜シネマ\) (ディスクリート)
\(Solotion:\)
- 愚かなタイトル、各言語の直接離散検索人
- 次に列挙映画は、その重量を計算し、最大のものは答えがあります
\(コード:\)
#include<stdio.h>
#include<map>
using namespace std;
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int m,ple=0,sat=0,fi=1,sci[200005],bn[200005],cn;
map<int,int> mp;
for(int i=0;i<n;i++)
{
scanf("%d",&sci[i]);
mp[sci[i]]++;
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&bn[i]);
}
for(int i=1;i<=m;i++)
{
scanf("%d",&cn);
if(mp[bn[i]]>ple)
{
ple=mp[bn[i]];
sat=mp[cn];
fi=i;
}
else if(mp[bn[i]]==ple&&mp[cn]>sat)
{
sat=mp[cn];
fi=i;
}
}
printf("%d\n",fi);
}
return 0;
}
\(3784 POJ ~~~実行メディア\) (ダイナミック中央値)
効果の件名:
列の数は、順次、すべての番号が追加されるの中央値を求めて、読み込まれます。
\(Solotion:\)
- 直接ライン上の小さな増加ルートルートヒープヒープのメンテナンスと
- 毎回両側のレコードの合計数は、それに添加された側決定されます
\(コード:\)
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
int n,t,x,a,b,cnt;
inline void read(int &x){
char ch=getchar();
char c=ch;
x=0;
while(ch<'0' || ch>'9') {
c=ch;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
if(c== '-') x=-x;
}
std::priority_queue <int> lq,sq;
int main(){
read(t);
while(t--){
read(cnt);
read(n);
while(!lq.empty()) lq.pop();
while(!sq.empty()) sq.pop();
cout<<cnt<<' '<<((n+1)/2)<<endl;
for(int i = 1;i <= n;++ i){
read(x);
lq.push(x);
sq.push(-x);
if(i%2==0) continue;
while(lq.top()!=-sq.top()){
a=lq.top();
lq.pop();
b=-sq.top();
sq.pop();
sq.push(-a);
lq.push(b);
}
cout<<lq.top()<<' ';
if(((i+1)/2)%10==0) puts("");
else if((n%2==1 && i==n) || (n%2==0 && i==n-1)) puts("");
}
}
return 0;
}
\(〜2299〜超POJクイックソート\) (順序を逆に)
効果の件名:
逆順の右に列を探しています。
\(Solotion:\)
- 私は、これは基本的なアルゴリズム、非常にノスタルジックを満たすだろうと思いました。
- 私たちは、木のそれは(離散必要)メンテナンス、およびフェンウィック最長の上昇系列ボードでの
\(POJ日焼け止め〜3614〜\) (貪欲、プライオリティキュー)
\(Solotion:\)
- このトピックでは、貪欲と考える方が簡単です
- 私たちは、牛や日焼け止めを分離ソートする日光の強さ(最小)です
- その後、我々は列挙日焼け止めと考えることができます
- 牛を守るために、現在の日焼け止めを保存することが順番にプライオリティキューを持ちます
- その後、我々は最小の牛日焼け止めと右端点(最大光強度)を得るために、優先キューを使用します
- これは確かに、より良い日光の最大の強さで、私たちは日焼け止めを残し日の最大の強みになりますので。
- 最小光強度が列挙時の(私たちは、その後、牛を守るために日焼け止めに追加されます)保証を取得します。
\(コード:\)
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define db double
#define rg register int
using namespace std;
int n,m,ans;
struct su{
int x,y;
inline bool operator <(const su &z)const{
return x<z.x;
}
}a[2505],b[2505];
struct pi{
int x,y;
inline bool operator <(const pi &z)const{
return y>z.y;
}
};
priority_queue<pi> q;
inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar()))if(ch=='-')sign=1;
while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
if(sign)return -res; else return res;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n=qr(); m=qr();
for(rg i=1;i<=n;++i)
a[i].x=qr(),a[i].y=qr();
sort(a+1,a+n+1);
for(rg i=1;i<=m;++i)
b[i].x=qr(),b[i].y=qr();
sort(b+1,b+m+1);
for(rg i=1,l=1;i<=m;++i){
while(l<=n&&a[l].x<=b[i].x){
pi x; x.x=l; x.y=a[l].y; q.push(x); ++l;
}
while(!q.empty()&&q.top().y<b[i].x)q.pop();
while(!q.empty()&&b[i].y){
++ans; --b[i].y; q.pop();
}
}printf("%d\n",ans);
return 0;
}
\(POJストール~~~ 3190予約\) (プレフィックスおよび優先キュー)
\(Solotion:\)
- この質問は、囲いの最小数を決定することです
- 私たちは、直接差分法とプレフィックスによって制約答えを得ることができます
- しかし、この道、我々はいくつかの囲いを使用されていないダイナミックを維持するために私たちを必要とする、出力番号を囲いする必要があります
- 私たちは、プライオリティキューの最適化を使用し、プレス左のエンドポイントは、各牛を列挙し、それが使用するプライオリティキューレコードの右端ポイントと囲いを使用し、(コラル使用状態、我々がしたいので、また(プライオリティキューを維持する必要があります囲いの数を最小限に抑えます))
- しかし、また、プライオリティキュー、次に列挙プロセスの動作を取り除くことに、費やした囲い記録病棟のプライオリティキューは行きます
\(コード:\)
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define db double
#define rg register int
using namespace std;
int n,tt,ans;
int as[50005];
struct su{
int l,r,id;
inline bool operator <(const su &x)const{
return l<x.l;
}
}a[50005];
struct pi{
int x,y;
inline bool operator <(const pi &z)const{
return x>z.x;
}
};
priority_queue<pi> q;
priority_queue<int, vector<int>, greater<int> >p;
inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar()))if(ch=='-')sign=1;
while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
if(sign)return -res; else return res;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n=qr();
for(rg i=1;i<=n;++i)
a[i].l=qr(),a[i].r=qr(),a[i].id=i,p.push(i);
sort(a+1,a+n+1);
for(rg i=1;i<=n;++i){
while(!q.empty()&&q.top().x<a[i].l){
p.push(q.top().y); q.pop();
}as[a[i].id]=p.top(); p.pop();
pi x; x.x=a[i].r; x.y=as[a[i].id]; q.push(x);
ans=max(ans,as[a[i].id]);
}
printf("%d\n",ans);
for(rg i=1;i<=n;++i)
printf("%d\n",as[i]);
return 0;
}