• 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
    */
    
    本欲起身离红尘,奈何影子落人间。
  • 相关阅读:
    orale 函数大全[转] 涛
    easyuicombobox的option选项为true与false时的问题 涛
    数据库镜像转移Failover Partner 涛
    创建链接服务器 涛
    Sql Server 2008 R2 清空数据库中ldf日志文件 涛
    杂 涛
    Jquery 数组操作大全【转载】 涛
    VS2012常用快捷键 涛
    android studio集成ijkplayer Vevi
    CenOs 部署记录 Vevi
  • 原文地址:https://www.cnblogs.com/jcgf/p/15245337.html
Copyright © 2020-2023  润新知