おしゃべり
今日の試験の良好な非友好的なああ。。。
\(T1 \)どのように数学の問題。。私は\(OI \)数学の最も弱いです。。
\(T2 \)暴力はまだ持たせる\を(60 \)ポイント、または許容生活の中でこんにゃくの目標は、まだここに停止するには
\(T3は、\)なぜ希望する\(DP \)このようなものを言って、ああ\(NOIP \)が、一回実行するごとに一日か二日をテストする必要があり、どのように前にテストしませんでした。。期待と数学の感覚と同じように、えっ何も知りません。。
フェイス質問
\(T1 \)
溶液
この質問はから、つまり、いくつかの要件の組み合わせに本質的である\(N \)選択の数\(M \)プログラム番号の数と同一でありません。しかし、この質問の条件、すなわち、離間それぞれ隣接する中間少なくとも二つの数\(K-1 \)の数。
我々は、デフォルト番号が最初に選択されたので、\(1 \) 、最後の番号が\(Nは\) 、次いで最後に加えて\(N \) 、各番号が有する背後\(K-1 \)数は、合計選択することができない\を((K-1)\回(M-1)\) 。
ここでも最後の1を除いて、我々は残りの中から選択する必要があります\(N-1-(K- 1)\回(M-1)\) 番号。
我々はこれらの数値にしたいので\(M-1 \)セグメント、少なくとも1つの番号を含む各セグメントは、要求のプログラム番号は、古典的な方法を用いて分離することができます。
答えは\(N-2- {C_(K-1)\タイムズ(1-M)M-2} ^ {} \)。
そして、被写体がルーカスの定理によると、パリティ答えを必要としているため。
\(\ tbinom {n}は{ K} \当量1 \(MOD \ 2)\) であれば、バイナリ場合にのみ、\は(Kは\)あなたよりも大きくない\(N- \) 、すなわち、対応するビットの\(N- \と\ K \ = K \ \) 、\(および\)ビット単位のANDです。
時間の複雑さ:\(O(T)\) 。
コード:
#include<bits/stdc++.h>
#define del(a,i) memset(a,i,sizeof(a))
#define ll long long
#define inl inline
#define il inl void
#define it inl int
#define ill inl ll
#define re register
#define ri re int
#define rl re ll
#define mid ((l+r)>>1)
#define lowbit(x) (x&(-x))
#define INF 0x3f3f3f3f
using namespace std;
template<class T>il read(T &x){
int f=1;char k=getchar();x=0;
for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;
for(;k>='0'&&k<='9';k=getchar()) x=(x<<3)+(x<<1)+k-'0';
x*=f;
}
template<class T>il print(T x){
if(x/10) print(x/10);
putchar(x%10+'0');
}
ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;}
it qpow(int x,int m,int mod){
int res=1,bas=x%mod;
while(m){
if(m&1) res=(res*bas)%mod;
bas=(bas*bas)%mod,m>>=1;
}
return res%mod;
}
int T,n,m,k;
int main()
{
freopen(".in","r",stdin);
freopen(".out","w",stdout);
read(T);
while(T--){
read(n),read(m),read(k);
puts(((((n-2-(m-1)*(k-1))&(m-2))==m-2)?"Yes\n" : "No\n"));
}
return 0;
}
\(T2 \)
溶液
この質問は、ソリューションの巨人で、私たちの部屋は、4つの首長を持っていた、それぞれのアプローチが異なっています。。。
考えてみましょう\(I、Jの\) 2点間\(j個\)する(私は\)\貢献を。
\(val_ {I、J} = dis_ {I、J} + C_I-c_j \)
これは木であるため、ルーチンの練習、即ちある\(dis_ {I、J} \) 離れては
\(val_ {I、J} = dis_i + dis_j-2 \回dis_ {LCA} + C_I-c_j \)
ここで\(DIS \)は、ノードからルートノードまでの距離を表します。
ときに(私は\)\決定、我々はその後、決定\(LCAを\) 、そして私たちは維持することができます\(MIN(dis_j-c_j) \) あなたはポイントを見つけることができます\(私は\)答えを。(二、三を使用する思考)
思考:木のDP
対応点、そのサブツリーにのみ選択された点の場合にツリーをルートと、
答えはツリーができる\(DP \)が再帰得ます。
そのサブツリーの外側の選択された点の場合を考えます。場合は、元の式の観察は、見つけることができます
父親ポイントは最適な選択のエクソンの木がします最適な選択ポイントではない
、その父親が最適である選択します。それ以外の場合は、サブツリーの外にその最良の選択でなければならない
父親の次善の選択肢。これにより、中\(DFS \)上からの起動時にすべてのポイント下に
そのサブツリーへの最高の答え。
各ツリーの内側と外側の最高のアイデアへの答えは、最小値は、各ポイントで得ることができる取る
の答え。
複雑さ:\(O(N)\) 。
クエリ時間計算:\(O(1)\) 。
\(PS:\)このアイデアはいいトラブルを感じます。。他の暴力で、ノーセグメントツリーのルート速いです。
分割統治ポイント:2を考えます
二点間の問題ツリーパスなので、澱粉を考えます。
ルートを維持することに加えて、出発点として、各ポイントを確実にするために、現在のパーティションに当センターを開くには、アイデアの初めによれば、左右のスイープに、左から右へサブツリー回(そして、同じ貢献のサブツリーの外側のすべての点)、あなたは異なるサブツリー内の2点間の値を取得することができます。その時、保守の各点については、\(最小\)の答えです。貢献は、サブツリーの全ての点のルートである\(最小\) 。
時間の複雑さ:\(O(N \ logN個)\) 。
クエリ時間計算:\(O(1)\) 。
セグメントツリールート変更:3を考えます
答えは、私たちが決定を検討し、オープンしました\(私は\)このツリーのルートのために、答えになる(最小(dis_j-C [\ \)J])を最小メンテナンス間隔で直接セグメントツリーを考えます。
ルートを変更することを検討してください。私たちはときに(私は\)\息子の\(k個\)新しいルートとして、我々は、このエッジのマイナス距離のルートにノードをルートノードのサブツリーが必要になりますこの長さを追加するには、ルートノードからの長さが、他の点、その後するクエリ、(K \)\最小のサブツリーのルートである、あなたは答えを更新することができます。
減算間隔を決定することができる(DFS \)\配列は、次いで従う\(DFS \)寄与に配列。
複雑さの前処理時間:\(O(N \ logN個)\) 。
クエリ時間計算:\(O(1)\) 。
アイデア4:忘れてました
コード
考えました:
#include <akari>
#define FI "skylines"
IO<1000000, 1000000> io;
cint N = 200003;
struct Node {
int x, qwq, dep, ans, mi;
struct Edge *e;
} g[N];
struct Edge {
Node *v;
int w;
Edge *e;
Edge() {}
Edge(Node *s, Node *t, cint x) : v(t), w(x), e(s->e) { s->e = this; }
} pool[N * 2], *curr = pool;
void arc(Node *u, Node *v, cint w) {
new (curr++) Edge(u, v, w);
new (curr++) Edge(v, u, w);
}
void dfs1(Node *u, Node *f) {
int &mi = u->mi = u->dep - u->x, tmi = INT_MAX;
int mc = 0;
Node *v;
go (e, u->e) if ((v = e->v) != f) {
v->dep = u->dep + e->w;
dfs1(v, u);
if (v->mi < tmi) tmi = v->mi, mc = 1;
else if (v->mi == tmi) ++mc;
}
if (mi < tmi) mc = 0;
else if (mi > tmi) mi = tmi;
else ++mc;
if (mc == 1 && mi != u->dep - u->x) {
Node *t;
int smi = u->dep - u->x;
go (e, u->e) if ((v = e->v) != f) {
if (v->mi == mi) t = v;
else smi = std::min(smi, v->mi), v->qwq = mi;
}
t->qwq = smi;
} else
go (e, u->e) if (e->v != f) e->v->qwq = mi;
u->ans = (tmi < INT_MAX) ? u->x - u->dep + tmi : INT_MAX;
}
void dfs2(Node *u, Node *f, cint t) {
if (t < INT_MAX)
u->ans = std::min(u->ans, u->dep + u->x + t);
Node *v;
go (e, u->e) if ((v = e->v) != f)
dfs2(v, u, std::min(t, v->qwq - 2 * u->dep));
}
int main() {
#ifndef AKARI
freopen(FI ".in", "r", stdin);
freopen(FI ".out", "w", stdout);
#endif
int n = io;
rep (i, 1, n)
io >> g[i].x;
re (i, 1, n) {
int u, v;
io >> u >> v;
arc(&g[u], &g[v], io);
}
dfs1(&g[1], NULL);
dfs2(&g[1], NULL, INT_MAX);
int q = io;
while (q--)
io << g[(int)io].ans daze;
}
2考えます:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
const int inf=2e9+10;
const int MAXN=2e5+10;
int ecnt=0,nx[MAXN<<1],to[MAXN<<1],val[MAXN<<1],head[MAXN];
void addedge(int u,int v,int w)
{
++ecnt;
to[ecnt]=v;
val[ecnt]=w;
nx[ecnt]=head[u];
head[u]=ecnt;
}
int n,m,c[MAXN],dist[MAXN],fa[MAXN];
int siz[MAXN],mxson[MAXN],vis[MAXN],Ans[MAXN];
int rt,mi,totsiz;
void Findrt(int u,int fa)
{
siz[u]=1;
int mxsiz=0;
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(v==fa || vis[v])
continue;
Findrt(v,u);
siz[u]+=siz[v];
mxsiz=max(mxsiz,siz[v]);
}
mxsiz=max(mxsiz,totsiz-siz[u]);
if(mxsiz<mi)
mi=mxsiz,rt=u;
}
int minv,rminv,tmp;
void dfs(int u,int F)
{
Ans[u]=min(Ans[u],minv+dist[u]+c[u]);
tmp=min(tmp,dist[u]-c[u]);
rminv=min(rminv,dist[u]-c[u]);
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(v!=F && !vis[v])
{
dist[v]=dist[u]+val[i];
dfs(v,u);
}
}
}
int stk[MAXN],tp=0;
void solve(int u)
{
dist[u]=0;
minv=-c[u],rminv=inf;
tp=0;
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(vis[v])
continue;
stk[++tp]=i;
tmp=inf;
dist[v]=val[i];
dfs(v,u);
minv=min(minv,tmp);
}
minv=dist[u]-c[u];
for(int i=tp;i>=1;--i)
{
int v=to[stk[i]];
tmp=inf;
dist[v]=val[stk[i]];
dfs(v,u);
minv=min(minv,tmp);
}
Ans[u]=min(Ans[u],rminv+c[u]);
}
void Divide(int u)
{
vis[u]=1;
solve(u);
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(vis[v])
continue;
totsiz=siz[v];
mi=inf;
Findrt(v,0);
Divide(rt);
}
}
void init()
{
mi=inf,totsiz=n;
Findrt(1,0);
Divide(rt);
}
int main()
{
freopen("skylines.in","r",stdin);
freopen("skylines.out","w",stdout);
n=read();
for(int i=1;i<=n;++i)
c[i]=read(),Ans[i]=inf;
for(int i=1;i<n;++i)
{
int u=read(),v=read(),w=read();
addedge(u,v,w);
addedge(v,u,w);
}
init();
int m=read();
for(int i=1;i<=m;++i)
{
int x=read();
printf("%d\n",Ans[x]);
}
return 0;
}
3思考:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 200010
#define INF 0x7ffffff
template <typename T>inline T read()
{
register T sum=0;
register char cc=getchar();
int sym=1;
while(cc!='-'&&(cc>'9'||cc<'0'))cc=getchar();
if(cc=='-')sym=-1,cc=getchar();
sum=sum*10+cc-'0';
cc=getchar();
while(cc>='0'&&cc<='9')sum=sum*10+cc-'0',cc=getchar();
return sym*sum;
}
template <typename T>inline T read(T &a)
{
a=read<T>();
return a;
}
template <typename T,typename... Others> inline void read(T& a, Others&... b)
{
a=read(a);
read(b...);
}
struct Edge
{
int v;
int w;
Edge *next;
Edge(int a=0,int b=0,Edge *c=NULL)
{
v=a;
w=b;
next=c;
}
}*head[maxn];
struct Node
{
int v;
int tag;
Node()
{
v=INF;
tag=0;
}
}node[maxn<<2];
int n,m,cnt,v[maxn],fa[maxn],ans[maxn],dis[maxn],dfn[maxn],tfn[maxn],siz[maxn];
void down(int k)
{
if(node[k].tag)
{
node[k<<1].v-=node[k].tag;
node[k<<1].tag+=node[k].tag;
node[k<<1|1].v-=node[k].tag;
node[k<<1|1].tag+=node[k].tag;
node[k].tag=0;
}
}
void build(int k,int l,int r)
{
if(l==r)
{
node[k].v=dis[tfn[l]]-v[tfn[l]];
return ;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
node[k].v=min(node[k<<1].v,node[k<<1|1].v);
}
void change(int k,int l,int r,int x,int y,int z)
{
if(l>=x&&r<=y)
{
node[k].v-=z;
node[k].tag+=z;
return ;
}
down(k);
int mid=(l+r)>>1;
if(x<=mid)change(k<<1,l,mid,x,y,z);
if(y>mid)change(k<<1|1,mid+1,r,x,y,z);
node[k].v=min(node[k<<1].v,node[k<<1|1].v);
}
int query(int k,int l,int r,int x,int y)
{
if(l>=x&&r<=y)return node[k].v;
down(k);
int mid=(l+r)>>1,ans=INF;
if(x<=mid)ans=min(ans,query(k<<1,l,mid,x,y));
if(y>mid)ans=min(ans,query(k<<1|1,mid+1,r,x,y));
return ans;
}
void dfs1(int k)
{
dfn[k]=++cnt;
tfn[cnt]=k;
siz[k]=1;
for(Edge *i=head[k];i!=NULL;i=i->next)
{
if(i->v==fa[k])continue;
fa[i->v]=k;
dis[i->v]=dis[k]+i->w;
dfs1(i->v);
siz[k]+=siz[i->v];
}
}
void print(int k,int l,int r)
{
if(l==r)
{
printf("%d ",node[k].v);
return ;
}
down(k);
int mid=(l+r)>>1;
print(k<<1,l,mid);
print(k<<1|1,mid+1,r);
}
void dfs2(int k)
{
for(Edge *i=head[k];i!=NULL;i=i->next)
{
if(i->v==fa[k])continue;
if(1<=dfn[i->v]-1)
change(1,1,n,1,dfn[i->v]-1,-i->w);
if(dfn[i->v]+siz[i->v]<=n)
change(1,1,n,dfn[i->v]+siz[i->v],n,-i->w);
change(1,1,n,dfn[i->v],dfn[i->v]+siz[i->v]-1,i->w);
ans[i->v]=INF;
if(1<=dfn[i->v]-1)
ans[i->v]=min(ans[i->v],query(1,1,n,1,dfn[i->v]-1));
if(dfn[i->v]+1<=n)
ans[i->v]=min(ans[i->v],query(1,1,n,dfn[i->v]+1,n));
ans[i->v]+=v[i->v];
dfs2(i->v);
if(1<=dfn[i->v]-1)
change(1,1,n,1,dfn[i->v]-1,i->w);
if(dfn[i->v]+siz[i->v]<=n)
change(1,1,n,dfn[i->v]+siz[i->v],n,i->w);
change(1,1,n,dfn[i->v],dfn[i->v]+siz[i->v]-1,-i->w);
}
}
int main()
{
freopen("skylines.in","r",stdin);
freopen("skylines.out","w",stdout);
n=read<int>();
for(int i=1;i<=n;i++)v[i]=read<int>();
for(int i=1;i<n;i++)
{
int x=read<int>(),y=read<int>(),z=read<int>();
head[x]=new Edge(y,z,head[x]);
head[y]=new Edge(x,z,head[y]);
}
dfs1(1);
build(1,1,n);
if(n>=2)ans[1]=query(1,1,n,2,n)+v[1];
dfs2(1);
m=read<int>();
for(int i=1;i<=m;i++)
printf("%d\n",ans[read<int>()]);
return 0;
}
\(T3 \)
溶液
かかわらず、列の数、それぞれの数だけのための重みと、一連の
関連する数
考えてみましょう\(DP \) 、各レコード番号に必要なステート数
見つけることができ、得られたソート済みの列の数は、二つの隣接する数字間の唯一の違いは、(0 \)を\
または\(1 \)
元のバイナリシーケンスの列の数によって維持差アレイは、各列の数表す
カウント数を
\(F(I、S)が \) 生成表す\を(私は\)番号、違いは既存の列の数である\(S \)はプログラムの数であります
列の数の各出現確率\(P_S = \ FRAC {F (M、S)} {M!} \)
事前に列挙数の転送のサイズは、あなたが状態を変更することができた場合
事前に前処理\(tot_Sが\)状態を示し\(S \)の重み列の数と表される、最終的な答えである\(\和\ limits_ {S } P_Stot_S \)
時間の複雑さ:\(O(M \ M cdot2 ^)\) 。除算を行う際乗法逆元のノートを使用して計算。
上記は、問題の内容解決策であるこんにゃくの外観は無知な力を表し見ます
コード
#include <akari>
#define FI "kiseki"
IO<100, 100> io;
const int N = 30, S = (1 << 24) + 5, mo = 998244353;
void add(int &x, cint v) {
if ((x += v) >= mo)
x -= mo;
}
int f_[S], g_[S], a[N], c[N], p[N], inv[N];
int main() {
#ifndef AKARI
freopen(FI ".in", "r", stdin);
freopen(FI ".out", "w", stdout);
#endif
int n;
io >> n >> n;
rep (i, 1, n)
io >> a[i];
inv[1] = 1;
rep (i, 2, n)
inv[i] = (ll)(mo - mo / i) * inv[mo % i] % mo;
int *f = f_, *g = g_;
f[0] = 1;
c[0] = 1;
rep (i, 2, n) {
re (s, 0, 1 << (i - 2)) {
int cur = 1;
c[1] = 1;
re (j, 0, i - 2) {
if ((s >> j) & 1) {
c[++cur] = 1;
p[cur] = j;
} else
++c[cur];
}
rep (j, 0, cur) {
int t;
if (j == 0)
t = s << 1;
else if (j == cur)
t = s | (1 << (i - 2));
else {
int h = s & ((2 << p[j + 1]) - 1);
t = ((s ^ h) << 1) | h;
}
g[t] = (g[t] + (ll)c[j] * inv[i] % mo * f[s]) % mo;
}
f[s] = 0;
}
std::swap(f, g);
}
int ans = 0;
re (s, 0, 1 << (n - 1)) {
int cur = 1;
int sum = a[1];
re (j, 0, n - 1) {
if ((s >> j) & 1)
++cur;
sum += a[cur];
}
ans = (ans + (ll)sum * f[s]) % mo;
}
io << ans daze;
return 0;
}
概要
こんにゃくや弱すぎるが、それを学ぶ来ます。。