NOIP2015リプレイ
D1T1 P2615魔法の魔方陣
言うまでもない直接シミュレーション、
NOIP2017予選それは好きzhenti
#include<cstdio>
const int maxn = 45;
int a[maxn][maxn];
int n, x, y;//x means heng, y means shu
void print()
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
printf("%d", a[i][j]);
if(j != n) printf(" ");
}
printf("\n");
}
}
int main()
{
//freopen("in.txt", "r", stdin);
scanf("%d", &n);
a[x = 1][y = (n + 1) / 2] = 1;
for(int i = 2; i <= n * n; i++)
{
if(x == 1 && y != n) x = n, y++;
else if(y == n && x != 1) y = 1, x--;
else if(x == 1 && y == n) x++;
else
{
if(x - 1 >= 1 && y + 1 <= n && a[x - 1][y + 1] == 0) x--, y++;
else x++;
}
a[x][y] = i;
//print();
//printf("\n");
}
print();
return 0;
}
D1T2 P2661メッセージング
最初は私はちょうど収集処理ソリューション内のSTLを使用したい、OIは、グラフ理論を学ぶ知りませんでしたが、T.てきました またはあまりにもナイーブああ!
誰かに伝えるのポイントとして抽象みんなに誕生日は明らかに答えが最も小さいリングの内側にある、でも有向エッジではありません。
私は3つのアプローチを見ました:
- キャノンは最小ユニコム強いコンポーネントのtarjan蚊を、戦います。
- 加重冷茶Kyiは最小のリングを見つけます。各それらの両方離れプラス1という、彼らの先祖に一点から記録まで先祖場合でも、異なる2点を、同じ祖先場合。最小値への答え。
- (自身が演じる)トポロジカル整列。0度は鳴るので、実際のトポロジカルソートに従わないでなければならないので削除されていると、最後にリングに真の残りの際に削除することはできません。一人一人も出て片側だけを持っているためと、ちょうどリングの皆様ので、直接OK最小のリングを見つけるDFS。
(熱分解ゾーンluoguP2661タイトルからコピー)は、第2および第3の符号を与えます。
#include<cstdio>
#include<iostream>
using namespace std;
int f[200002],d[200002],n,minn,last; //f保存祖先节点,d保存到其祖先节点的路径长。
int fa(int x)
{
if (f[x]!=x) //查找时沿途更新祖先节点和路径长。
{
int last=f[x]; //记录父节点(会在递归中被更新)。
f[x]=fa(f[x]); //更新祖先节点。
d[x]+=d[last]; //更新路径长(原来连在父节点上)。
}
return f[x];
}
void check(int a,int b)
{
int x=fa(a),y=fa(b); //查找祖先节点。
if (x!=y) {f[x]=y; d[a]=d[b]+1;} //若不相连,则连接两点,更新父节点和路径长。
else minn=min(minn,d[a]+d[b]+1); //若已连接,则更新最小环长度。
return;
}
int main()
{
int i,t;
scanf("%d",&n);
for (i=1;i<=n;i++) f[i]=i; //祖先节点初始化为自己,路径长为0。
minn=0x7777777;
for (i=1;i<=n;i++)
{
scanf("%d",&t);
check(i,t); //检查当前两点是否已有边相连接。
}
printf("%d",minn);
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
int n,t[200050],d[200050],ans=1000000000,r[200050];
void read(int& x){
x=0;
int y=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') y=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
x=x*y;
}
void dfs(int ti,int s,int l){
if (ti==s&&l){ //如果回到开始说明连成了环
ans=min(ans,l);
return;
}
if (!d[t[ti]]) {
d[t[ti]]=1; //标记
dfs(t[ti],s,l+1);
}
}
void rmove(int ti){ //删除ti
d[ti]=-1; //标记
r[t[ti]]--; //ti的下一个人的入度减一
if (!r[t[ti]]&&d[t[ti]]!=-1) rmove(t[ti]);
}
int main(){
memset(d,0,sizeof(d));
memset(r,0,sizeof(r)); //r[i]为第 i 个人的入度
int i;
read(n);
for (i=1;i<=n;i++){
read(t[i]);
r[t[i]]++;
}
for (i=1;i<=n;i++){
if (!r[i]&&d[i]!=-1) rmove(i); //如果 i 的入度为 0 且还未被删除,则删除i
}
for (i=1;i<=n;i++){
if (!d[i]){ //如果i还未搜过且未被删除,则从i开始搜索
//cout<<i<<' ';
dfs(i,i,0);
}
}
printf("%d",ans);
return 0;
}
D1T3 P2668地主
大がん問題の大規模なシミュレーションを検索!地主は終了しません
この質問は(または他のそれを行うことはできません)カードのこれらのタイプのいくつかの方法の合計であります:
ストアカードは、必要なカードの唯一の少数の色を必要としません。便宜上、あなたは理由Aの存在と2非常に面倒で、対応するチンカードの標準を設定することができます。
アイデアは、大きな暴力、エネルギーバンドの有無にかかわらず列挙し、単一またはペアを再生するためにカード上に散在残りの正しい作品です。全体的なフレームワークは、バックトラックを置きます。
揚げたとき王は以前扱っていない、最後のペアまたは単一の処置を置くことができます。
最初のターン3、ストレートシングルとダブルストレートストレートに考えられ、暴力の最長は、直接オフ、ストレート正当見つけます。
次に、4本のベルトと三つのゾーンを検討します。一例として、四つのゾーンは、の4つの揚げ、その後、2と3つの部分、二対と対と4と4のうち1、4本のベルトIとIVの他の部分に分け、そして最後に爆弾を忘れてはいけない見つけてみましょう。三つのゾーンでは、3枚のカードを選び出すことができ、同じ理由です。
実際には、唯一残っている、シングル、ダブル、王のペアのみ。私たちはライン上で普通の他のカードと同様に、同じカードとして2人の王を置きます。
最後にとき残りのカード0の状態で、それが答えに含まれ、現在の答えよりも小さい場合。
もちろん、あなたが最適な剪定の混乱をすることができます。
プラスこれよりもはるかに難しいです!
コード:
#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 25;
const int order[15] = {0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 2, 0};
const int INF = 0x3f3f3f3f;
int card[maxn];
int n, ans;
int read()
{
int ans = 0, s = 1;
char ch = getchar();
while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0', ch = getchar();
return s *ans;
}
void dfs(int left, int res)
{
if(res >= ans) return;
if(left == 0)
{
ans = std::min(ans, res);
return;
}
for(int i = 1; i <= 11; i++)// san shun zi
{
if(card[order[i]] >= 3)
{
int p;
for(p = i + 1; p <= 12; p++)
{
if(card[order[p]] < 3) break;
}
p--;
if(p - i + 1 >= 2)
{
for(int j = i; j <= p; j++) card[order[j]] -= 3;
dfs(left - (p - i + 1) * 3, res + 1);
for(int j = i; j <= p; j++) card[order[j]] += 3;
}
}
}
for(int i = 1; i <= 10; i++)// shuang shun zi
{
if(card[order[i]] >= 2)
{
int p;
for(p = i + 1; p <= 12; p++)
{
if(card[order[p]] < 2) break;
}
p--;
if(p - i + 1 >= 3)
{
for(int j = i; j <= p; j++) card[order[j]] -= 2;
dfs(left - (p - i + 1) * 2, res + 1);
for(int j = i; j <= p; j++) card[order[j]] += 2;
}
}
}
for(int i = 1; i <= 8; i++)// dan shun zi
{
if(card[order[i]] >= 1)
{
int p;
for(p = i + 1; p <= 12; p++)
{
if(card[order[p]] < 1) break;
}
p--;
if(p - i + 1 >= 5)
{
for(int j = i; j <= p; j++) card[order[j]]--;
dfs(left - (p - i + 1), res + 1);
for(int j = i; j <= p; j++) card[order[j]]++;
}
}
}
for(int i = 1; i <= 13; i++)// si dai
{
if(card[order[i]] >= 4)
{
card[order[i]] -= 4;
for(int j = 1; j <= 14; j++)
{
if(card[order[j]] >= 2)
{
card[order[j]] -= 2;
for(int k = j; k <= 14; k++)
{
if(card[order[k]] >= 2)
{
card[order[k]] -= 2;
dfs(left - 8, res + 1);// si dai liang dui
card[order[k]] += 2;
}
}
dfs(left - 6, res + 1);// si dai yi dui
card[order[j]] += 2;
}
}
for(int j = 1; j <= 14; j++)
{
if(card[order[j]] >= 1)
{
card[order[j]]--;
for(int k = j; k <= 14; k++)
{
if(card[order[k]] >= 1)
{
card[order[k]]--;
dfs(left - 6, res + 1);// si dai liang zhang
card[order[k]]++;
}
}
dfs(left - 5, res + 1);// si dai yi zhang
card[order[j]]++;
}
}
dfs(left - 4, res + 1);// zha dan
card[order[i]] += 4;
}
}
for(int i = 1; i <= 13; i++)// san dai
{
if(card[order[i]] >= 3)
{
card[order[i]] -= 3;
for(int j = 1; j <= 14; j++)
{
if(card[order[j]] >= 2)
{
card[order[j]] -= 2;
dfs(left - 5, res + 1);// san dai yi dui
card[order[j]] += 2;
}
if(card[order[j]] >= 1)
{
card[order[j]]--;
dfs(left - 4, res + 1);// san dai yi zhang
card[order[j]]++;
}
}
dfs(left - 3, res + 1);// san zhang pai
card[order[i]] += 3;
}
}
for(int i = 1; i <= 14; i++)
{
if(card[order[i]] == 1 || card[order[i]] == 2)
{
left -= card[order[i]];
res++;
}
}
if(left == 0) ans = std::min(ans, res);
}
int main()
{
int T = read(); n = read();
while(T--)
{
memset(card, 0, sizeof card);
ans = INF;
for(int i = 1; i <= n; i++)
{
int x = read(), y = read();
card[x]++;
}
dfs(n, 0);
printf("%d\n", ans);
}
return 0;
}
D2T1 P2678ジャンプ石
古典的な二分法の回答の質問を取得します。
単調に件名が見つかりました:最短距離が小さくジャンプ、あまり必要性Bandiao石、そしてときの最短距離より大きなジャンプ、より多くの必要性Bandiao石であるとき。
ほとんど削除するので、ちょうど\(M \)とき岩を、最短距離の最大値をジャンプ。
だから、答えはバイナリ思考を決定することで、解答を決定する方法について考え始める\(中旬\)適格性を?
チェック機能は、一般的に貪欲です。我々は最短距離のジャンプを決定すると、前の現在地点からの最短距離よりも小さいジャンプ、そう答えは最短距離のジャンプではありません、削除する必要があります。外に移動し、どのように多くのブロック合計で見る必要があるの次の反復した後、以下の場合には、\(M \)は、正当な以上ない場合は、正当なものです。
コード:
#include<cstdio>
using namespace std;
const int maxn = 50005;
int l, n, m;
int d[maxn];
int ans;
bool check(int x)
{
int last = 0, cnt = 0;
for(int i = 1; i <= n; i++)
{
if(d[i] - d[last] < x)
{
cnt++;
}
else last = i;
}
if(cnt <= m) return true;
return false;
}
int main()
{
scanf("%d%d%d", &l, &n, &m);
d[0] = 0;
for(int i = 1; i <= n; i++) scanf("%d", &d[i]);
d[n + 1] = l;
int left = 1, right = l;
while(left <= right)
{
int mid = (left + right) >> 1;
if(check(mid)) ans = mid, left = mid + 1;
else right = mid - 1;
}
printf("%d\n", ans);
return 0;
}
D2T2 P2679サブストリング
ピットが充填されます