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
*/