2021.08.27 膜你赛

2021.08.27 膜你赛

seq

Description

小杜给了小 \(q\) 一个数列,数列长度为 \(n\),数列元素分别为
$a_1 ,a_2 ,...,a_n $。

小杜跟小 \(q\) 说,数列的元素不能随意改动,但是小杜允许小 \(q\) 对数列做如下操作:选择一个数字 \(i(1<=i<=n)\),然后将 \(a_i\) 替换成 \(a_i'\) 其中 \(a_i'= a_i \oplus (2^k -1)\),\(\oplus\) 为异或操作。并且这样的操作次数可以为 \(0\) 到任意多次。

小 \(q\) 不 喜 欢 数 字 \(0\) , 所 以 小 \(q\) 想 让 尽 可 能 多 的 区 间 \([l,r](1<=l<=r<=n)\) 满足如下条件:\(a_l \oplus a_{l + 1} \oplus ... \oplus a_r ≠ 0\),
那么最多能有多少不同的区间满足条件呢?

Solution

求异或前缀和,找出 \(sum,sum^k\) 的较小值排序,将相同的数放在一起,然后将他们尽量向后放。

Code

/*
* @Author: smyslenny
* @Date:    2021.08.27
* @Title:   
* @Main idea:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#include <ctime>

#define TIME (double)clock() / CLOCKS_PER_SEC
#define int long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)

using namespace std;
const int mod=998244353;
const int M=2e5+5;
int n,k,Ans,mp[M];
double st;
int read()
{
	int x=0,y=1;
	char c=getchar();
	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
	return y?x:-x;
}
namespace substack1{
	int Ans,js,sum[15];
	void get_Ans()
	{
		js=0;
		for(int i=1;i<=n;i++)
			sum[i]=sum[i-1]^mp[i];
		for(int l=1;l<=n;l++)
			for(int r=l;r<=n;r++)
				if(sum[r]^sum[l-1])
					js++;
		Ans=max(Ans,js);
		memset(sum,0,sizeof(sum));
	}
	void dfs(int x)//枚举异或序列 
	{
		if(x>n) 
			return; 
		for(int i=x;i<=n;i++)
		{
			mp[i]^=k;
			get_Ans();
			dfs(i+1);
			mp[i]^=k;
			get_Ans();
			dfs(i+1);
			
		}
		return;
	}
	void main()
	{
		for(int i=1;i<=n;i++) mp[i]=read();
		dfs(1);
		printf("%lld\n",Ans);
	}
}
namespace substack2{ //错的,想错题了,再想想 
	int sum[M],js,Max;
	void main()
	{
		for(int i=1;i<=n;i++) mp[i]=read();
		for(int i=0;i<=n;i++)
		{
			mp[i]^=k;js=0;
			for(int j=1;j<=n;j++)
				sum[j]=sum[j-1]^mp[j];
			for(int l=1;l<=n;l++)
				for(int r=l;r<=n;r++)
					if(sum[r]^sum[l-1])
						js++;
			Max=max(Max,js);
			mp[i]^=k;
		}
		printf("%lld\n",Max);
	}
}
namespace substack3{
	int sum[M],re,js;
	void main()
	{
		sum[0]=0;
		for(int i=1;i<=n;i++) mp[i]=read(),sum[i]=sum[i-1]^mp[i];//前缀异或和 
		for(int i=1;i<=n;i++) sum[i]=min(sum[i],sum[i]^k);//找出最小的 
		sort(sum,sum+1+n);js=0;//拍一下序,让相同的数凑到一起 
		Ans=(n+1)*n/2;//所有的区间 
		for(int i=0;i<=n;i++)
		{
			if(i==0 || sum[i]==sum[i-1]) js++;//记录相等的个数 
			else { 
				if(js&1){re=js/2;Ans-=re*(re-1)/2;re=js/2+1;Ans-=re*(re-1)/2;}//奇数的话, 
				else {re=js/2;Ans-=re*(re-1);}js=1;}//是搜书 
		}
		if(js&1){re=js/2;Ans-=re*(re-1)/2;re=js/2+1;Ans-=re*(re-1)/2;}
		else re=js/2,Ans-=re*(re-1);
		printf("%lld\n",Ans);
	}
}

signed main()
{
//	freopen("seq.in","r",stdin);
//	freopen("seq.out","w",stdout); 
	srand(time(NULL));
	n=read(),k=read();
	k=(1<<k)-1;
	Ans=n;
	if(n<=10) substack1::main();
//	else if(k==1) substack2::main();
	else
		substack3::main();
	return 0;
}
/*
10 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

6 3 
1 4 4 7 3 4
*/

	

path

Description

你有一个 \(n \times n\) 的矩阵,矩阵的每个元素有一个小写字母,你可以对矩阵的至多 \(k\) 个字母做修改,即把一个字母改成任意一个小写字母。

我们认为所有的路径都是如下定义的:一条从左上角出发,每次只能移动到它右边一个位置或者它下面一个位置,并且最终到达右下角,这条路径的值定义为一个字符串,即为路径上所有的小写字母按照移动的先后顺序排列成的字符串,很显然字符串的长度为 \(2n-1\)。

现在你需要找出在至多进行 \(k\) 次修改之后所有路径的值的字典序最小值。

Solution

直接搜索,正解是 dp,当时考试的时候写了dp但是发现不对去写的搜索。

Code

/*
* @Author: smyslenny
* @Date:    2021.08.
* @Title:   
* @Main idea: dp? 搜索? 
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>

#define ll long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)

using namespace std;
const int mod=998244353;
const int M=2e3+5;
int n,k;
int mp[M][M],f[M][M],Ans[M],js;
char s[M];
int read()
{
	int x=0,y=1;
	char c=getchar();
	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
	return y?x:-x;
}
int Min=INF,now;
void dfs(int x,int y,int las)
{
	if(x>n || y>n || x<1 || y<1) return;
	if(x==n && y==n)
	{
		if(k)
			Min=min(Min,las*10+1);
		else
			Min=min(Min,las*10+mp[n][n]);
		return;
	}
	if(las*10+mp[x][y]>Min) return; 
	if(k && mp[x][y]!=1)
	{
		if(x!=n)
		{
			k--;
			f[x][y]=las*10+1;
			dfs(x+1,y,f[x][y]);
			f[x][y]--;
			f[x][y]/=10;
			k++;
		}
		if(y!=n)
		{
			k--;
			f[x][y]=las*10+1;
			dfs(x,y+1,f[x][y]);
			f[x][y]--;
			f[x][y]/=10;
			k++;
		}
	}
	else
	{
		if(x!=n)
		{
			f[x][y]=las*10+mp[x][y];
			dfs(x+1,y,f[x][y]);
			f[x][y]-=mp[x][y];
			f[x][y]/=10;
		}
		if(y!=n)
		{
			f[x][y]=las*10+mp[x][y];
			dfs(x,y+1,f[x][y]);
			f[x][y]-=mp[x][y];
			f[x][y]/=10;
		}
	}
}
		
int main()
{
//	freopen("path.in","r",stdin);
//	freopen("path.out","w",stdout); 
	n=read(),k=read();
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for(int j=1;j<=n;j++) mp[i][j]=s[j]-'a'+1;
	}
	dfs(1,1,0);
	while(Min)
	{
		Ans[++js]=Min%10-1+'a';
		Min/=10;
	}
	for(int i=js;i>=1;i--)
		printf("%c",(char)Ans[i]);
	return 0;
}
/*
 
4 0 abcd bcde bcad bcde
4 2
zzza
zaaa
zaaa
zaaa
4 2
ccbb
zbbb
bbbb
aaaa
5 2
zccbb
zcbbb
zbbbb
aaaaa
aaaaa
*/

bus

\(smyslenny\) 每天都坐公交车上学。\(smyslenny\) 的家和学校都在 \(P\) 城,\(P\) 城有 \(n\) 个公交车站,编号为 \(1\) 到 \(n\),\(smyslenny\) 家在 \(1\) 号公交车站处,学校在 \(n\) 号 公交车站处。 \(P\) 城有 \(m\) 辆公交车,每辆公交车只从某个站台到另一个站台,且 每天只运行一次,出发时间和到达时间确定,且中途不停靠任何公交
车站。\(smyslenny\) 可以进行换乘,只需要在下一辆公交车的出发时间或者出发 时间之前到达公交车站即可。\(smyslenny\) 一共要上 \(Q\) 天的学,每天的时间都不完全相同,\(smyslenny\) 是一个 很懒的人,\(smyslenny\) 想知道最迟什么时候到达 \(1\) 号公交车站才能够到学校 不迟到呢?要是你帮助了 \(Smyslenny\) ,\(YCC\) 可以给你 \(¥998244353\) 哦。

Solution

按照我的思路,对于读入的边,我们都反向连边,然后搜每条边能够到达的最远距离的最大时间,但是有两个点 T 了,正解好像是 dp

Code

/*
* @Author: smyslenny
* @Date:    2021.08.27
* @Title:   
* @Main idea:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>

#define ll long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)

using namespace std;
const int mod=998244353;
const int M=3e5+5;
int n,m,Q;
int read()
{
	int x=0,y=1;
	char c=getchar();
	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
	return y?x:-x;
}
struct ed{
	int u,v,s,w,t,net;
}edge[M<<1];
int point[M];
int head[M],num;
void addedge(int u,int v,int s,int t)
{
	edge[++num].u=u;
	edge[num].v=v;
	edge[num].s=s;
	edge[num].t=t;
	edge[num].w=-INF;
	edge[num].net=head[u];
	head[u]=num;
}
int Ans;
int dfs(int u,int fa,int tim)
{
	if(u==1) {Ans=tim;return tim;}
	for(int i=head[u];i;i=edge[i].net)
	{
		int v=edge[i].v;
		if(v==fa) continue;
		if(edge[i].t<=tim)
		{
			edge[i].w=max(edge[i].w,dfs(v,u,edge[i].s));
		}
		else
			edge[i].w=edge[i].s;
	}
	return Ans;
}

int main()
{
//	freopen("bus.in","r",stdin);
//	freopen("bus.out","w",stdout);
	n=read(),m=read();
	for(int i=1,u,v,s,t;i<=m;i++)
	{
		u=read(),v=read(),s=read(),t=read(); 
		addedge(v,u,s,t);
	}
	dfs(n,0,INF);
	Q=read();
	while(Q--)
	{
		int tim=read(),Ans=-1;
		for(int i=head[n];i;i=edge[i].net)
		{
			if(tim>=edge[i].t)
				Ans=max(Ans,edge[i].w);
		}
		printf("%d\n",Ans);
	}
	return 0;
}
/*
5 6
1 2 10 25 
1 2 12 30
2 5 26 50 
1 5 5 20 
1 4 30 40 
4 5 50 70 
4
10
30
60
100
*/
上一篇:Django学习


下一篇:djangorestframework token 认证