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
*/
本欲起身離紅塵,奈何影子落人間。