T1 回文
這種經典的\(dp\)就是不會做,就是不會。。。。。
除了\(dp\)數組不會設其他的都跟題解差不多,然而並沒有啥用。。。。
設\(dp[len][x1][x2]\)表示回文串的一半長度為\(len\),從\((1,1)\)開始的串這時終點的橫坐標為\(x1\),從\((n,m)\)開始的串終點的橫坐標為\(x2\)
然后分情況轉移即可
最后在一條對角線,也就是回文中心處統計答案
palin
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int NN=501,mod=993244853;
namespace AE86{
FILE *wsn;
auto read=[](){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
};
auto write=[](int x,char opt='\n'){
char ch[20];short len=0;if(x<0)x=~x+1,putchar('-');
do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
for(short i=len-1;i>=0;--i){putchar(ch[i]);}putchar(opt);
};
}using namespace AE86;
int n,m,a[NN][NN],len;
int dp[2][NN][NN];
char s[NN];
namespace WSN{
inline short main(){
wsn=freopen("palin.in","r",stdin);
wsn=freopen("palin.out","w",stdout);
n=read(); m=read(); len=n+m-2>>1;
for(int i=1;i<=n;i++){scanf("%s",s+1);
for(int j=1;j<=m;j++)a[i][j]=s[j]-'a';
}
if(a[1][1]!=a[n][m]) return puts("0"),0;
dp[0][1][n]=1;
for(int i=0;i<len;i++){
int x1=min(n,i+1),x2=max(1ll,n-i);
memset(dp[i+1&1],0,sizeof(dp[i+1&1]));
for(int j=1;j<=x1;j++){
int y1=i-j+2;
for(int k=n;k>=x2;k--){
int y2=n+m-k-i;
if(j<n&&y2>1) if(a[j+1][y1]==a[k][y2-1]) (dp[i+1&1][j+1][k]+=dp[i&1][j][k])%=mod;
if(j<n&&k>1) if(a[j+1][y1]==a[k-1][y2]) (dp[i+1&1][j+1][k-1]+=dp[i&1][j][k])%=mod;
if(y1<m&&y2>1)if(a[j][y1+1]==a[k][y2-1]) (dp[i+1&1][j][k]+=dp[i&1][j][k])%=mod;
if(y1<m&&k>1) if(a[j][y1+1]==a[k-1][y2]) (dp[i+1&1][j][k-1]+=dp[i&1][j][k])%=mod;
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
(ans+=dp[len&1][i][i])%=mod;
if((n+m&1)&&i<n) (ans+=dp[len&1][i][i+1])%=mod;
} write(ans);
return 0;
}
}
signed main(){return WSN::main();}
T2 快速排序
確實像大結論題,不過覺得考場上差點就分析出來了,可是最終還是沒有。。。。
發現他排序的過程在以\(nan\)為\(left\)的時候,\(nan\)的相對位置不會變
所以直接掃一遍,掃到一個不是\(nan\)的數就把小於這個數的數全部輸出
是\(nan\)直接輸出\(nan\)
qsort
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int NN=5e5+5;
namespace AE86{
FILE *wsn;
auto read=[](){
int x=0;bool f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='a'){f=0,ch=getchar();break;}ch=getchar();}
if(!f) return -1ll;
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x;
};
auto write=[](int x,char opt='\n'){
char ch[20];short len=0;if(x<0)x=~x+1,putchar('-');
do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
for(short i=len-1;i>=0;--i){putchar(ch[i]);}putchar(opt);
};
}using namespace AE86;
int T,n,stk[NN],top;
struct number{bool isnan;int value;}a[NN];
multiset<int> s;
auto solve=[](){
n=read(); s.clear();
for(int i=1;i<=n;i++){
int x=read();if(x>0)s.insert(x);
a[i]=x<0?number{1,x}:number{0,x};
}
for(int i=1;i<=n;i++){
if(a[i].isnan) printf("nan ");
else{
if(s.find(a[i].value)==s.end())continue;
multiset<int>::iterator it=s.begin();
while(*it<a[i].value){
stk[++top]=*it;
++it;
}
for(int j=1;j<=top;j++)
s.erase(s.find(stk[j])),printf("%lld ",stk[j]);
top=0; printf("%lld ",*it); s.erase(it);
}
}
puts("");
};
namespace WSN{
inline short main(){
wsn=freopen("qsort.in","r",stdin);
wsn=freopen("qsort.out","w",stdout);
T=read();while(T--)solve();
return 0;
}
}
signed main(){return WSN::main();}
T3 混亂邪惡
應\(OMA\)的委托,決定把這道題的題解寫成論文。。。。。
\(\color{red}{\huge{Warning}}\)
考慮這道題的限制會把原來的數組變成什么樣子
\(\{a_1,a_2,\dots,a_n\}\)是\(\{1,2,\dots,m\}\)的子集
這個保證了所有的\(a_i\)互不相同,並且值域確定了
\(\lfloor\frac{2m}{3}\rfloor <n\leq m\)
這個保證了\(a\)數組中一定有一串等差數列,並且公差為\(1\)
這個不難證明,因為在\([1,m]\)中最多只有\(\frac{m}{2}\)個偶數或者奇數,
如果保證兩個數之間的差值都大於\(1\)顯然是不可能的,因為\(n\in (\frac{2m}{3},m]\)
所以排完序之后一定有一段序列是公差為\(1\)的等差數列,即奇數偶數都有
保證\(\sum a_i\)為偶數
這個限制保證了\(a\)數組中一定有偶數個奇數
考慮如果沒有限制的情況下,數組\(a\)有幾種情況
不難發現,數組\(a\)要么都是偶數,要么有偶數個奇數,否則無法滿足\(\sum a_i\in even\)
而前面的限制保證了\(a\)數組無法都是偶數,那么數組中只能有偶數個奇數
這樣我們就分析出來了數組\(a\)構造上的幾個性質:
- 所有數互不相同,值域在\([1,m]\)之間
- 一定有一串公差為一的等差數列
- 數組中一定有偶數個奇數
然后我們考慮如何構造。
如果數列長度為奇數,我們給他再加上一個元素\(0\),這樣就保證了數組長度為偶數,以便我們后面分組
我們把數組\(a\)進行升序排序,然后相鄰的兩兩為一組,並記錄\(d_i=a_{2i}-a_{2i-1}\)
然后我們記錄\(sm=\sum d_i\),這個值是我們“預構造”出的方案的偏差值(即和正確的構造方案多了多少數)
然后我們按照\(d_i\)降序的順序進行“選擇”
發現差值為\(d_i\)的一組元素如果交換位置關系,即\(a_{2i},a_{2i-1}\)交換
會對\(sm\)產生\(2d_i\)的影響,即\(sm-2d_i\),那么我們“選擇”的過程就是消除原本的構造方案差值的過程
這樣,我們就實現了對這道題的構造,並沒有不合法的方案(如果你不想看證明了,現在就可以開始愉快的切題了)
我們開始大面積證明這樣構造的正確性。。。。
首先,顯然,加入一個元素\(0\)不會對答案產生影響
那么我們考慮為什么一定沒有不合法方案
發現每次交換元素位置產生的總貢獻一定是一個偶數,那么我們現在要證明的問題變為了\(\sum d_i\in even\),
start
我們構造的前提是數組長度為偶數,又有偶數個奇數,則一定有偶數個偶數
那么分兩種情況討論,
- 偶數個數大於奇數
這時我們排完序后的序列一部分肯定是奇數偶數交錯的,這時兩兩分組一定會產生偶數對兒奇數偶數匹配
他們的差值是奇數,有偶數個差值,這一部分的\(\sum d\)為偶數,剩下的更好說,偶數偶數配對差值都是偶數
這種情況得證
- 偶數個數小於奇數
前面奇數偶數交錯的部分跟前面一樣,后面剩下的一定是偶數個奇數,他們匹配差值都是偶數,也得證
end
證明完\(\sum d\)為偶數后,發現證明的問題為差值從大到小進行消除一定有合法的解
不難發現如果所有的差值都被選擇最終\(sm<0\)(因為\(sm\)是\(d\)加出來的,拿\(2d\)去減它一定會使他小於零)
而我們會想到有一種情況可能會無解,即當\(sm=2\)時最小的差值是\(2\)或者更大,這樣減完就會是負的,\(2-2*2<0\)
那么我們現在要找一種讓差值盡可能都\(\geq 2\)的數列,如果他也有解,那么所有的的數列都有解,所有的問題就都解決了
那么我們考慮把\([1.m]\)中的偶數都選上,這樣會有\(\frac{m}{2}\)個偶數,那么剩下的\(\frac{2m}{3}-\frac{m}{2}\)個數只能是奇數
不妨把他們規定為\(1,3,5,...\),因為其他的跟這幾個都一樣的
我們發現有長度為\(2\times(\frac{2m}{3}-\frac{m}{2})\)的公差為一的等差數列
這樣兩兩分組后差值為\(1\)的二元組就會有\(\frac{2m}{3}-\frac{m}{2}=\frac{m}{6}\)這么多個,剩下\(\frac{n}{2}-\frac{m}{6}\)組偶數保證其差值\(\geq 2\)
然后我們發現\(sm\leq m-\frac{n}{2}<n\)(唯獨不知道這里是為什么,題解上說的就用吧)
\(\color{red}{饃饃zxs證明已經給到下面了}\)
確實不用考慮那個加一的問題,因為下面的不等式部分取值極限取不到(比如n>\(\frac{2m}{3}\),這樣取到這個值最后的不等式符號是小於,加上\(1\)之后頂多是小於等於\(0\))
那么\(sm-4\times(\frac{n}{2}-\frac{m}{6})\leq m-\frac{n}{2}-2n+\frac{2m}{3}\leq \frac{5m}{3}-\frac{5n}{2}\leq \frac{5m}{3}-\frac{5}{2}\times \frac{2m}{3}< 0\)
所以不用差值為一的二元組就可以把\(sm\)消完,如果發現\(sm-2*d<0\)則可以找前面的差值為\(1\)的去消,那么以上的構造都是合理的
\(\color{red}{\huge{證完啦,手殘啦!!!}}\)
不過我會很佩服能夠從上面一直看到這里的人,我反正是沒有這個耐心的(向你致敬~~)
chaoticevil
#include<bits/stdc++.h>
using namespace std;
const int NN=1e6+5;
namespace AE86{
FILE *wsn;
auto read=[](){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
};
auto write=[](int x,char opt='\n'){
char ch[20];short len=0;if(x<0)x=~x+1,putchar('-');
do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
for(short i=len-1;i>=0;--i){putchar(ch[i]);}putchar(opt);
};
}using namespace AE86;
int n,m,sm,c[NN];
vector<pair<int,int> > t;
struct node{int val,id;}a[NN];
namespace WSN{
inline short main(){
wsn=freopen("chaoticevil.in","r",stdin);
wsn=freopen("chaoticevil.out","w",stdout);
n=read();m=read();
for(int i=1;i<=n;++i)a[i]=node{read(),i};
if(n&1) a[++n]=node{0,n};
sort(a+1,a+n+1,[](node x,node y)->bool{return x.val<y.val;});
for(int i=1,d;i<=n;i+=2){
d=a[i+1].val-a[i].val;
t.push_back(make_pair(d,i)); sm+=d;
c[a[i+1].id]=1; c[a[i].id]=-1;
}
sort(t.begin(),t.end());
for(int i=t.size()-1,v,id;~i;--i){
v=t[i].first,id=t[i].second;
if(sm>=v*2)
sm-=v*2,swap(c[a[id].id],c[a[id+1].id]);
else if(sm==0){
puts("NP-Hard solved");if(!a[1].val)--n;
for(int j=1;j<=n;++j)printf("%d ",c[j]);
puts(""); return 0;
}
}
return 0;
}
}
signed main(){return WSN::main();}
T4 校門外歪脖樹上的鴿子
正在改,拼命改
\(upd 2021.11.7\)
pigeons
#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int NN=4e5+5; namespace AE86{FILE *wsn;auto read=[](){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;};auto write=[](int x,char opt='\n'){char ch[20];short len=0;if(x<0)x=~x+1,putchar('-');do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);for(short i=len-1;i>=0;--i){putchar(ch[i]);}putchar(opt);};}using namespace AE86;
int n,m,rng,ch[NN][2],fa[NN],root;
int ll[NN],rr[NN],len[NN],lst[NN],rst[NN];
map<int,int>mp[NN];
inline int pos(int x){return ch[fa[x]][1]==x;}
inline int bro(int x){return x==root?root:ch[fa[x]][pos(x)^1];}
inline void build(int x){
ll[x]=rr[x]=x;
if(ch[x][0])build(ch[x][0]),ll[x]=ll[ch[x][0]];
if(ch[x][1])build(ch[x][1]),rr[x]=rr[ch[x][1]];
if(ll[x]>rr[x]) swap(ch[x][0],ch[x][1]),ll[x]=ll[ch[x][0]],rr[x]=rr[ch[x][1]];
len[x]=rr[x]-ll[x]+1; mp[ll[x]][rr[x]]=x;
}
namespace tree_division{
int dfn[NN],rk[NN],dep[NN],siz[NN],son[NN],top[NN],cnt;
inline void dfs1(int f,int x){
dep[x]=dep[f]+1; siz[x]=1;
if(x==root) lst[x]=rst[x]=x;
else lst[x]=pos(x)?x:lst[fa[x]],rst[x]=pos(x)?rst[fa[x]]:x;
if(ch[x][0]) dfs1(x,ch[x][0]),siz[x]+=siz[ch[x][0]];
if(ch[x][1]) dfs1(x,ch[x][1]),siz[x]+=siz[ch[x][1]];
son[x]=(siz[ch[x][0]]>siz[ch[x][1]])?ch[x][0]:ch[x][1];
}
inline void dfs2(int x,int t){
top[x]=t; dfn[x]=++cnt; rk[cnt]=x;if(!son[x]) return; dfs2(son[x],t);
(son[x]==ch[x][0])?dfs2(ch[x][1],ch[x][1]):dfs2(ch[x][0],ch[x][0]);
}
inline int LCA(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);x=fa[top[x]];
}if(dfn[x]>dfn[y]) swap(x,y);
return x;
}
inline int findrt(int x,int y){
x=top[x];
while(x!=top[y])if(fa[x]==y)return x;else x=top[fa[x]];
return son[y];
}
}using namespace tree_division;
struct SNOWtree{
#define lid (id<<1)
#define rid (id<<1|1)
int ll[NN<<2],rr[NN<<2],w[NN<<2],sm[NN<<2],laz[NN<<2];
inline void pushup(int id){if(ll[id]!=rr[id])sm[id]=sm[lid]+sm[rid];}
inline void down(int id,int v){sm[id]+=v*w[id];laz[id]+=v;}
inline void pushdown(int id){if(ll[id]!=rr[id]&&laz[id])down(lid,laz[id]),down(rid,laz[id]),laz[id]=0;}
inline void build(int id,int l,int r,int opt){
ll[id]=l;rr[id]=r;if(l==r)return w[id]=(pos(bro(rk[l]))!=opt)?len[bro(rk[l])]:0,void();
int mid=(l+r)>>1; build(lid,l,mid,opt); build(rid,mid+1,r,opt); w[id]=w[lid]+w[rid];
}
inline void modify(int id,int l,int r,int v){
if(l<=ll[id]&&rr[id]<=r) return down(id,v),void(); pushdown(id);
int mid=ll[id]+rr[id]>>1;if(l<=mid)modify(lid,l,r,v);if(r>mid)modify(rid,l,r,v);pushup(id);
}
inline int query(int id,int l,int r){
if(l<=ll[id]&&rr[id]<=r)return sm[id];pushdown(id);int mid=ll[id]+rr[id]>>1,ans=0;
if(l<=mid) ans+=query(lid,l,r);if(r>mid) ans+=query(rid,l,r); return ans;
}
inline void update(int x,int y,int v){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
modify(1,dfn[top[x]],dfn[x],v);x=fa[top[x]];
}if(dfn[x]>dfn[y])swap(x,y);modify(1,dfn[x]+1,dfn[y],v);
}
inline int calc(int x,int y,int ans=0){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans+=query(1,dfn[top[x]],dfn[x]);x=fa[top[x]];
}if(dfn[x]>dfn[y])swap(x,y);return ans+query(1,dfn[x]+1,dfn[y]);
}
}tr[2];
inline void update(int x,int v){tr[pos(x)^1].modify(1,dfn[bro(x)],dfn[bro(x)],v);}
inline int query(int x){return tr[pos(x)^1].query(1,dfn[bro(x)],dfn[bro(x)]);}
int opt,x,y,d,lca;
auto solve=[](){
opt=read();x=read();y=read();lca=LCA(x,y);
// cout<<opt<<" "<<x<<" "<<y<<" "<<lca<<endl;
if(opt==1){
d=read();
if(mp[x].find(y)!=mp[x].end()) return update(mp[x][y],d),void();
int X=lst[x],Y=rst[y];
if(dep[X]<=dep[lca]) update(findrt(x,lca),d);
else update(X,d),tr[0].update(X,findrt(x,lca),d);
if(dep[Y]<=dep[lca]) update(findrt(y,lca),d);
else update(Y,d),tr[1].update(Y,findrt(y,lca),d);
}else{
if(mp[x].find(y)!=mp[x].end()) return write(query(mp[x][y])),void();
int X=lst[x],Y=rst[y],ans=0;
if(dep[X]<=dep[lca]) ans+=query(findrt(x,lca));
else ans+=query(X)+tr[0].calc(X,findrt(x,lca));
if(dep[Y]<=dep[lca]) ans+=query(findrt(y,lca));
else ans+=query(Y)+tr[1].calc(Y,findrt(y,lca));
write(ans); return;
}
};
namespace WSN{
inline short main(){
wsn=freopen("pigeons.in","r",stdin);
wsn=freopen("pigeons.out","w",stdout);
n=read();m=read();rng=2*n-1;
for(int i=n+1;i<=rng;i++){
ch[i][0]=read();ch[i][1]=read();
fa[ch[i][0]]=fa[ch[i][1]]=i;
} for(int i=n+1;i<=rng;i++)if(!fa[i]){root=i;break;}
build(root);dfs1(0,root);dfs2(root,root);
tr[0].build(1,1,rng,0);tr[1].build(1,1,rng,1);
while(m--)solve();
return 0;
}
}
signed main(){return WSN::main();}