【Matrica】
洛谷
模擬
首先,除了對角線以外都是兩兩對稱的。
所以,如果有一個字母的個數爲奇數,那麼必須有一個放對角線上。
如果奇數字母的個數大於了(邊長),就了。
數據三萬,我們顯然不能一個一個地填,只能求出詢問列的字母就可以了。
由於填的的數要求沿對角線對稱,所以只用求一半。
__
___
_____
______
僅僅是單數填對角線可能不夠,所以還要把幾對的字母填入,而剩下的部分可以直接填,所以我們先填對角線。
先把字母排個序,求一下前綴和。
當前在第行列時,如果可以填雙數的,且字母排序小,則連續填入兩個,代表當前已經用了多少個(不算當前填的這個),這樣用前綴和就可以判斷排到哪個字母了。
注意,雙數的一定是兩個兩個填,所以一開始我就除以了二,更新時,仔細推一推,不要算錯了。
填完對角線後,把用過的數量都減去,再求一次前綴和。
同樣的,填每一列時,我們都可以統計,算出每一位該填哪個字母,然後存入數組。
行小於列時,推一推更新。
行等於列時,直接用之前算出的填入。
行大於列時,沿對角線對稱,再推。
注:注意卡常,把我從卡到了!!!
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=3e4+5;
#define re register
int n,k,b[30],cnt=0,q,ans[N],u=0,e[51];
struct node{int v,num,sum;}a[30];
char s[4],c[N][51];
inline bool comp(const node &x,const node &y){
return x.v<y.v;
}
int main(){
n=read();k=read();
for(re int i=1;i<=k;i++){
scanf("%s",s);
a[i].v=s[0]-'A';a[i].num=read();
if(a[i].num%2){a[i].num--;b[++cnt]=a[i].v;u++;}
a[i].num/=2;
}
if(u>n){printf("IMPOSSIBLE");return 0;}
sort(a+1,a+k+1,comp);
for(re int i=1;i<=k;i++)a[i].sum=a[i-1].sum+a[i].num;
sort(b+1,b+cnt+1);
for(re int i=1,r=0,use=(n-u)/2,n1=1,n2=1;i<=n;i++){
while(a[n1].sum<=r&&n1<=k)n1++;
if((n2<=cnt&&n1<=k&&b[n2]<=a[n1].v)||!use){ans[i]=b[n2++];r+=n-i;}
else{ans[i]=ans[i+1]=a[n1].v;a[n1].num--;use--;r+=n-i+n-i;i++;}//
}
for(re int i=1;i<=k;i++)a[i].sum=a[i-1].sum+a[i].num;
q=read();
for(re int i=1;i<=q;i++)e[i]=read();
sort(e+1,e+q+1);
for(re int i=1,x,r,n1;i<=q;i++){
r=x=e[i];r-=2;n1=1;
for(re int j=1;j<=x;j++){
if(x==j){c[j][i]=(char)(ans[x]+'A');r++;continue;}
while(a[n1].sum<=r)n1++;
c[j][i]=(char)(a[n1].v+'A');
r+=n-j-1;
}
for(re int j=x+1;j<=n;j++){
while(a[n1].sum<=r)n1++;
c[j][i]=(char)(a[n1].v+'A');
r++;
}
}
for(re int i=1;i<=n;i++){
for(re int j=1;j<=q;j++)
putchar(c[i][j]);
putchar('\n');
}
return 0;
}
【BST】
洛谷
雙向鏈表
容易發現,插入的數,只會最終接在的前驅或後繼的下一層,深度較大的那一個的兒子節點上。
可以用雙向鏈表,倒序刪除節點求之前的前驅後繼。
詳情看代碼就懂了。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=3e5+4;
int n,a[N],l[N],r[N],pre[N],nxt[N],dep[N];
long long ans=0;
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
l[i]=i-1;r[i]=i+1;//模擬鏈表
}
r[n]=0;dep[0]=-1;
for(int i=n;i;i--){
pre[a[i]]=l[a[i]];
nxt[a[i]]=r[a[i]];//記錄答案
r[l[a[i]]]=r[a[i]];
l[r[a[i]]]=l[a[i]];//刪除該節點,更新左右
}
for(int i=1;i<=n;i++){
dep[a[i]]=max(dep[pre[a[i]]],dep[nxt[a[i]]])+1;
ans+=dep[a[i]];
printf("%lld\n",ans);
}
return 0;
}
【Najkraci】
洛谷
最短路
拓撲排序
題目大意:給定一個個點條邊的有向圖。(點的編號從到)每條邊上有權,表示邊連接的兩點間的距離(注意是有向邊)。點到點的路徑的長度爲,所經過的所有邊的權值之和。到的最短路爲所有路徑中長度最小的一個。
你的工作是對於每條邊,輸出有多少條最短路經過它。(結果對求餘)
?洛谷數據有問題?
每一個點作爲起點跑一遍,把最短路上的邊重新建一個圖,一定是,可以用拓撲排序。
:從起點到的最短路個數
]:從到其他點的最短路個數
對於邊,加上答案
注意不要寫錯了,剛開始建的圖不要和新建的搞錯了。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int mod=1e9+7,N=1505,M=5005;
int dis[N],vis[N],n,m,ans[M],fl[M],in[N];
struct edge{int u,v,w,nxt;}e[M*2],a[M*4];
int first[N],cnt=0,head[N];
inline void add(int u,int v,int w){
e[++cnt].v=v;e[cnt].u=u;e[cnt].w=w;
e[cnt].nxt=first[u];first[u]=cnt;
}
inline void add2(int u,int v,int w){
a[++cnt].u=u;a[cnt].v=v;a[cnt].w=w;
a[cnt].nxt=head[u];head[u]=cnt;
}
inline void dij(int s){
priority_queue< pair<int,int> >q;
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(fl,0,sizeof(fl));
q.push(make_pair(0,s));//
dis[s]=cnt=0;
while(!q.empty()){
int x=q.top().second;q.pop();
if(vis[x])continue;
vis[x]=1;
for(int i=first[x],v;i;i=e[i].nxt){
v=e[i].v;
if(dis[v]>dis[x]+e[i].w){
dis[v]=dis[x]+e[i].w;
q.push(make_pair(-dis[v],v));
}
}
}
}
int f[N],g[N];//s到i有多少種 i到其他有多少種 保證爲DAG
int main(){
n=read();m=read();
for(int i=1,u,v,w;i<=m;i++){
u=read();v=read();w=read();
add(u,v,w);
}
for(int i=1;i<=n;i++){
dij(i);//要保存老圖
memset(head,0,sizeof(head));
memset(in,0,sizeof(in));
for(int j=1;j<=m;j++)
if(dis[e[j].u]+e[j].w==dis[e[j].v]){
fl[j]=1;in[e[j].v]++;
add2(e[j].u,e[j].v,e[j].w);
}
memset(f,0,sizeof(f));
f[i]=1;
queue<int>q;
q.push(i);
while(!q.empty()){
int u=q.front();q.pop();
for(int j=head[u],v;j;j=a[j].nxt){
v=a[j].v;
f[v]+=f[u];
in[v]--;
if(!in[v])q.push(v);
}
}
memset(head,0,sizeof(head));
memset(in,0,sizeof(in));
for(int j=1,x=cnt;j<=x;j++){
add2(a[j].v,a[j].u,a[j].w);
in[a[j].u]++;
}
fill(g+1,g+n+1,1);
for(int j=1;j<=n;j++)
if(!in[j])q.push(j);
while(!q.empty()){
int u=q.front();q.pop();
for(int j=head[u],v;j;j=a[j].nxt){
v=a[j].v;
g[v]+=g[u];
in[v]--;
if(!in[v])q.push(v);
}
}
for(int j=1;j<=m;j++)
if(fl[j])ans[j]=(ans[j]+(long long)f[e[j].u]*g[e[j].v]%mod)%mod;
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}