9.22 正睿提高4
阿新 • • 發佈:2018-09-25
== 是我 += 只需要 路徑 cpp sdoi putchar http
。這樣兩邊的\(a\)是對稱的,所以兩個\(0\)始終是\(0\)(左邊右邊相等)。
而且\(a[1\sim n]\)兩邊都是\(0\),所以最後的\(a[1\sim n]\)就是我們要求的。
當然判左右點的時候根據這個判下下標就好了,不需要建出環來。。
目錄
2018.9.22 正睿提高5 - A 數組計數(DP)
- B 旅行(思路)
- C 進化(思路 二進制拆分)
- 考試代碼
- B
- C
2018.9.22 正睿提高5
時間:3.5h
期望得分:100+80+30
實際得分:100+80+30
比賽鏈接
T2一直以為類似某道虛樹題(SDOI2015)。。到最後只想寫暴力(寫了暴力也該想到了啊 但是已經在劃水了)。
A 數組計數(DP)
題目鏈接
DP。前綴和優化一下就行了。
剛開始滾動數組又少清空了mmp。。
#include <cstdio> #include <cctype> #include <algorithm> #define gc() getchar() #define Mod(x) x>=mod&&(x-=mod) #define mod 998244353 typedef long long LL; const int N=1e6+5; int f[2][N],sum[2][N]; inline int read() { int now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-'0',c=gc()); return now; } int main() { int n=read(),K=read(),now=1,las=0; for(int i=1; i<=n; ++i) f[0][i]=1,sum[0][i]=i;//f[1] for(int i=2; i<=K; ++i) { for(int j=i; j<=n; ++j) f[now][j]=sum[las][j>>1]; sum[las][i-1]=sum[now][i-1]=0; for(int j=i; j<=n; ++j) sum[now][j]=sum[now][j-1]+f[now][j], Mod(sum[now][j]); now=las, las^=1; } printf("%d\n",f[las][n]); return 0; }
B 旅行(思路)
題目鏈接
如果當前到了\(i\),那麽除了\(1\)到\(a_i\)的邊走一次,剩下的\(1\)到\(a_1,a_2,...,a_{i-1}\)的路徑不與到\(a_i\)重疊的部分都要走兩次。
假設到\(a_i\)還要回到\(1\),那麽只需要把所有走過的邊計算兩次。最後減去\(a_i\)到\(1\)的距離即可(深度)。
//92ms 6616kb #include <cstdio> #include <cctype> #include <algorithm> //#define gc() getchar() #define MAXIN 200000 #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++) typedef long long LL; const int N=1e5+7; int Enum,H[N],nxt[N<<1],to[N<<1],fa[N],dep[N]; bool vis[N]; char IN[MAXIN],*SS=IN,*TT=IN; inline int read() { int now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-'0',c=gc()); return now; } inline void AE(int u,int v) { to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum; to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum; } void DFS(int x) { for(int i=H[x],v; i; i=nxt[i]) if((v=to[i])!=fa[x]) fa[v]=x,dep[v]=dep[x]+1,DFS(v); } int main() { int n=read(),q=read(); for(int i=1; i<n; ++i) AE(read(),read()); DFS(1), vis[1]=1; for(int i=1,a,ans=0; i<=q; ++i) { a=read(); for(int x=a; !vis[x]; x=fa[x]) vis[x]=1,ans+=2; printf("%d\n",ans-dep[a]); } return 0; }
C 進化(思路 二進制拆分)
題目鏈接
設a為原數組,b為進化一次後的數組,c為進化兩次後的數組。
則\(c_i=b_{i-1}\oplus b_{i+1}=a_{i-2}\oplus a_i\oplus a_i\oplus a_{i+2}=a_{i-2}\oplus a_{i+2}\)。
通過打表還可以發現,a進化\(2^d\)次後的數組c,滿足\(c_i=a_{i-2^d}\oplus a_{i+2^d}\)。
所以進化\(2^d\)後的數組可以\(O(n)\)求。
對T二進制拆分就行了。(對啊,\(2^a+2^b\)次後的就是\(2^a\)次後的再進化\(2^b\)次)
還有邊界的問題。我們可以構造一個環來保證這是正確的:\(0\ a[1\sim n]\ 0\ a[n\sim 1]\)
而且\(a[1\sim n]\)兩邊都是\(0\),所以最後的\(a[1\sim n]\)就是我們要求的。
當然判左右點的時候根據這個判下下標就好了,不需要建出環來。。
//39ms 720kb
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define pc putchar
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e5+5;
bool A[N],B[N];
char IN[MAXIN],*SS=IN,*TT=IN;
inline LL read()
{
LL now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
int main()
{
LL T=read(); int n=read();
register char c=gc(); for(;!isdigit(c);c=gc());
bool *now=A, *las=B;
now[1]=c-'0';
for(int i=2; i<=n; ++i) now[i]=gc()-'0';
int len=2*n+2;
for(LL d=1; T; T>>=1,d<<=1)
if(T&1)
{
std::swap(now,las);
for(int i=1; i<=n; ++i)
{
int l=i-d%len, r=i+d%len;
if(l<0) l=-l;//關於0對稱啊
if(l>n) l=len-l;
if(r>len) r-=len;
if(r>n) r=len-r;
now[i]=las[l]^las[r];
}
}
for(int i=1; i<=n; ++i) pc(now[i]+'0');
return 0;
}
考試代碼
B
#include <set>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define MAXIN 200000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e5+7;
int n,q,A[N],dgr[N],Enum,H[N],nxt[N<<1],to[N<<1],fa[N],dep[N],sz[N],son[N],top[N],dfn[N+3],ref[N+3];
LL Ans;
bool vis[N],mark[N];
std::set<int> st;
char IN[MAXIN],*SS=IN,*TT=IN;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline void AE(int u,int v)
{
++dgr[v], to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
++dgr[u], to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
inline int LCA(int u,int v)
{
while(top[u]!=top[v]) dep[top[u]]>dep[top[v]]?u=fa[top[u]]:v=fa[top[v]];
return dep[u]>dep[v]?v:u;
}
inline int Dis(int u,int v)
{
if(!u||!v) return 0;
return dep[u]+dep[v]-(dep[LCA(u,v)]<<1);
}
inline bool cmp_dfn(int a,int b)
{
return dfn[a]<dfn[b];
}
void DFS1(int x)
{
int mx=0; sz[x]=1;
for(int i=H[x],v; i; i=nxt[i])
if((v=to[i])!=fa[x])
{
fa[v]=x, dep[v]=dep[x]+1, DFS1(v), sz[x]+=sz[v];
if(sz[v]>mx) mx=sz[v], son[x]=v;
}
}
void DFS2(int x,int tp)
{
static int Index;
top[x]=tp, ref[dfn[x]=++Index]=x;
if(son[x])
{
DFS2(son[x],tp);
for(int i=H[x]; i; i=nxt[i])
if(to[i]!=fa[x]&&to[i]!=son[x]) DFS2(to[i],to[i]);
}
}
bool Subtask4()
{
for(int i=2; i<=n; ++i) if(dgr[i]>1) return 0;
int ans=0;
if(A[1]!=1) ++ans; printf("%d\n",ans);
for(int i=2; i<=q; ++i)
{
if(A[i]==1) printf("%d\n",ans+1);
else ans+=2, printf("%d\n",ans);
}
return 1;
}
bool DFS3(int x,int s)
{
bool fl=0;
for(int i=H[x],v; i; i=nxt[i])
if((v=to[i])!=fa[x])
fl|=DFS3(v,(mark[v]?1:2));
if(fl||vis[x]) Ans+=s;
return fl||vis[x];
}
void Subtask2()
{
for(int i=1,ai; i<=q; ++i)
{
vis[ai=A[i]]=1;
for(int p=ai; p!=1; p=fa[p]) mark[p]=1;
Ans=0, DFS3(1,0), printf("%lld\n",Ans);
for(int p=ai; p!=1; p=fa[p]) mark[p]=0;
}
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n=read(), q=read();
for(int i=1; i<n; ++i) AE(read(),read());
DFS1(1), DFS2(1,1);
for(int i=1; i<=q; ++i) A[i]=read();
if(Subtask4()) return 0;
if(n<=4000) return Subtask2(),0;
// Subtask2();
int mx=0;//Chain
for(int i=1,ai; i<=q; ++i)
{
ai=A[i];
if(dep[ai]>mx) printf("%d\n",mx=dep[ai]);
else printf("%d\n",mx+mx-dep[ai]);
}
// /*st.insert(0),*/ st.insert(N);
// LL ans=Dis(1,A[1]); printf("%lld\n",ans);
// st.insert(1); if(A[1]!=1) st.insert(dfn[A[1]]);
//
// std::set<int>::iterator pre,nxt;
// for(int i=2,ai,tmp; i<=q; ++i)//不對哎...但是還是能用來過鏈吧 算了
// {
// ai=A[i];
// int last=ref[*(--st.rbegin())];
// tmp=Dis(last,ai);
// printf("%lld\n",ans+tmp);
//
// if(ai==1) continue;
//
// pre=st.upper_bound(dfn[ai]), nxt=pre--;
// if(*nxt==N) ans+=Dis(ai,ref[*pre]);
// else ans+=Dis(ai,ref[*pre])+Dis(ai,ref[*nxt])-Dis(ref[*pre],ref[*nxt]);
//
// st.insert(dfn[ai]);
// }
return 0;
}/*
10 6
1 2 2 3 1 4 4 6 4 10 4 5 5 7 5 8 5 9
10 1 7 8 3 6
6 5
1 2 2 3 3 4 5 4 6 5
2 5 3 6 1
10 9
1 2 3 2 3 4 4 5 5 6 6 7 7 8 9 8 10 9
7 2 3 1 9 10 4 6 5
*/
C
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define pc putchar
#define gc() getchar()
#define MAXIN 300000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e5+5;
bool A[N],B[N];
char IN[MAXIN],*SS=IN,*TT=IN;
inline LL read()
{
LL now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
void Output(bool *a,int n)
{
// for(int i=1; i<=n; ++i) pc(a[i]+'0'),pc(' '); pc('\n');
for(int i=1; i<=n; ++i)
{
if(a[i]) pc('$');
else pc('_');
pc(' ');
}
pc('\n');
}
void Subtask1(int T,int n)
{
for(int i=1; i<=T; ++i)
{
B[1]=A[2], B[n]=A[n-1];
for(int i=2; i<=n; ++i) B[i]=A[i-1]^A[i+1];
memcpy(A,B,sizeof A);
// printf("%d:\t",i); Output(A,n);
}
for(int i=1; i<=n; ++i) pc(A[i]+'0');
}
int main()
{
// freopen("my.out","w",stdout);
LL T=read(); int n=read();
register char c=gc(); for(;!isdigit(c);c=gc());
A[1]=c-'0';
for(int i=2; i<=n; ++i) A[i]=gc()-'0';
if(T<=1000) return Subtask1(T,n),0;
return 0;
}/*
100 5
00100
1000 20
11100001110100010101
*/
9.22 正睿提高4