1. 程式人生 > 其它 >2021 8.21 模擬測試

2021 8.21 模擬測試

T1

將字母按字典序列舉,將每一個字母儘量往首位移動,若無法滿足,則向下一個列舉,對於一個字母該移動多少位,答案應該是\(pos-tot-1\),tot是前面要多少個字母被移動過,我們發現每一個字母對\(tot\)的影響是對從\(pos\)一直到末位,所以可以聯想到樹狀陣列或線段樹的區間修改單點查值,用一個樹狀陣列維護這道題就完了

#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define int long long
#define in read()
using namespace std;
inline int read()
{
    int data=0,w=1; char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
queue<int> q[27];
int c[500010],ans[500010];
int n,k,l=1,num=0,len;
void update(int k,int val) {while(k<=len) c[k]+=val,k+=lowbit(k);}
int query(int k)
{
	int ans=0;
	while(k>0) ans+=c[k],k-=lowbit(k);
	return ans;
}
signed main()
{
//	freopen("escape.in","r",stdin);
//	freopen("escape.out","w",stdout);
	n=in,k=in;
	string s;
	cin>>s;len=s.size();
	for(int i=0;i<len;i++)
	{
		int a=s[i]-'a'+1;
		q[a].push(i+1);
	}
	while(n--)
	{
		for(int i=1;i<=26;i++)
		{
			if(q[i].empty()) continue;
			int pos=q[i].front();
			int sum=pos-query(pos)-1;
			if(k>=sum)
			{
				k-=sum;
				ans[l]=pos;
				l++;
				update(pos,1);
				q[i].pop();
				break;
			}
		}
	}
	for(int i=1;i<l;i++)
	{
		printf("%c",s[ans[i]-1]);
	}
}

T2

對於這道題我們可以發現當一個點對答案的貢獻其實就是以這個點為中心的所有低於它的所有路徑的組合,設這些路徑是\(S_1,S_2,S_3……S_i\),總和為\(T\),那麼一個點的貢獻就是

\[S_1\times(T-S_1)+S_2\times(T-S_2)+……+S_i\times(T-S_i) \]

化簡一下可以得到

\[T^2-S_1^2-S_2^2-……-S_i^2 \]

於是我們只要找到每一個點周圍有多少個小於它的點即可,對於這個我們可以考慮兩次\(dfs\),第一次存下子樹內的答案,第二次從根往下遞推求出答案

#include<bits/stdc++.h>
#define re register
#define ll long long
#define in read()
using namespace std;
inline int read()
{
    int data=0,w=1; char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
const int N=300030;
int n;
struct edge{
	int u,v,nxt;
}e[N<<1];
int first[N],cnt=1;
ll f[N],g[N],d[N];//子樹內答案,總答案,平方和
ll ans;
inline void add(int u,int v){e[++cnt]=(edge){u,v,first[u]};first[u]=cnt;}

void dfs1(re int u,re int fa)
{
	for(re int i=first[u];i;i=e[i].nxt)
	{
		re int v=e[i].v;
		if(v==fa)continue;
		dfs1(v,u);
		if(u>v)
		{
			f[u] += f[v]+1;
			d[u] += 1ll*(f[v]+1)*(f[v]+1);
			g[u] = f[u];
		}
	}
}

void dfs2(re int u,re int fa)
{
	for(re int i=first[u];i;i=e[i].nxt)
	{
		re int v=e[i].v;
		if(v==fa)continue;
//		cerr<<u<<" "<<v<<"\n";
		if(v>u)
        {
			g[v] += g[u]+1;
			d[v] += (g[u]+1)*(g[u]+1);
		}
		dfs2(v,u);
	}
}

int main()
{
	// int size=100<<20;
	// __asm__ ("movq %0, %%rsp\n"::"r"((char*)malloc(size)+size));
	n=in;
	for(re int i=1;i<n;i++){
		re int u=in,v=in;
		add(u,v),add(v,u);
	}
	dfs1(1,0);
//	for(re int i=1;i<=n;i++)cout<<f[i]<<"\n";
	dfs2(1,0);
//	for(re int i=1;i<=n;i++)cout<<g[i]<<"\n";
	for(re int i=1;i<=n;i++) ans += 1ll*g[i]*g[i]-1ll*d[i];
	write(ans);
	exit(0);
}

T3

由於不是見到那路徑,且邊權皆為\(1\),所以對於任意一個\(d\),若\(d\)為奇數,且\(d≥\)奇數到達終點的最短路徑,那麼\(d\)一定可以,同理偶數亦是如此,所以我們就可以分奇偶性來討論,即維護一個奇偶最短路徑與\(d\)比較即可。
時間複雜度\(O(n^2)\),但空間還需要優化,所以可以離線省掉起點那一維。
還有此題需要特別多的特判

#include<bits/stdc++.h>
#define N 5050
#define M 100010
#define in read()
using namespace std;
inline int read()
{
    int data=0,w=1; char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
int n,m,q;
struct edge{
	int u,v,nxt;
}e[N<<1];
struct query{
	int s,t,d,ans,id;
}p[M];
int dis[N][2],vis[N];
int first[N],cnt;
inline void add(int u,int v){e[++cnt]=(edge){u,v,first[u]};first[u]=cnt;}
inline bool cmp1(query a,query b){return a.s<b.s;}
inline bool cmp2(query a,query b){return a.id<b.id;}
queue<int>que;
void spfa(int s)
{
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	que.push(s);
	dis[s][0]=0;//不可能在0時為奇數邊 
	int flag=0;//特判 
	while(!que.empty())
	{
		int u=que.front();que.pop();vis[u]=0;
		for(int i=first[u];i;i=e[i].nxt)
		{
			flag=1;
			int v=e[i].v;
			if(dis[v][0]>dis[u][1]+1)
			{
				dis[v][0]=dis[u][1]+1;
				if(!vis[v]) que.push(v),vis[v]=1;
			}
			if(dis[v][1]>dis[u][0]+1)
			{
				dis[v][1]=dis[u][0]+1;
				if(!vis[v]) que.push(v),vis[v]=1;
			}
		}
	}
	if(!flag) dis[s][0]=0x3f3f3f3f;
}
int main()
{
	n=in,m=in,q=in;
	for(int i=1,u,v;i<=m;i++) u=in,v=in,add(u,v),add(v,u);
	for(int i=1;i<=q;i++)
	{
		int x=in,y=in,d=in;if(x>y) swap(x,y);
		p[i].s=x,p[i].t=y,p[i].d=d,p[i].id=i;
	}
	sort(p+1,p+q+1,cmp1);
	int num=0;
	while(1)
	{
		if(num>=q) break;
		int s=p[++num].s,flag=0;
		spfa(s);
		while(s==p[num].s)
		{
			if(!p[num].d) p[num].ans=(s==p[num].t);
			else p[num].ans=(dis[p[num].t][p[num].d&1]<=p[num].d);
			num++;flag=1;
		}
		if(flag) num--;
	}
	sort(p+1,p+q+1,cmp2);
	for(int i=1;i<=q;i++)
	{
		if(p[i].ans) puts("Yes");
		else puts("No");
	}
}

T4

不會,先咕著吧