2021.08.24 膜你賽
2021.08.24 膜你賽
monitor
Description
監聽的宇宙電波可以抽象成一個長度為 \(L\) 的小寫字母組成的字串。
同時在三體人總結出來了 \(n\) 段敏感電波的樣子,每段敏感電波的長度都是 \(m\)。
現在請你實現一個程式,求出在這長度為 \(L\) 的小寫字母組成的字串中某個敏感電波第一次出現的位置(位置從 \(1\) 開始計數)。如果從頭到尾,沒有任何敏感電波出現,輸出”\(no\)”(不帶雙引號).
Solution
看到多個模式串一個文字串,立馬想到了AC自動機,把模板敲上之後發現處理答案的時候其實並不用根據什麼fail指標去跳,看題解裡提了幾句AC自動機,但是沒講具體是怎麼過的,根據AC自動機的原理,在對文字串進行操作的時候,是根據trie樹向下找的,那我們如果當前到達了一個根節點,之前肯定到了上面的點,並且是連續依次到達的,因此只要掃一遍當前點是否是根節點,是的話直接輸出開始點的位置,也就是 now-m+2
Code
/* * @Author: smyslenny * @Date: 2021.08.23 * @Title: * @Main idea: 感覺是 AC自動機板子題 */ #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=1e5+5; int n,m,l,Ans=INF,js,pos[M]; char S[M][30],T[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; }struct tr{ int ch[26],fail,cnt; } void insert(int x) { int u=0; for(int i=0;i<m;i++) { int num=S[x][i]-'a'; if(!tree[u].ch[num]) tree[u].ch[num]=++js; u=tree[u].ch[num]; } tree[u].cnt++; pos[x]=u; } int fg; int main() { // freopen("monitor.in","r",stdin); // freopen("monitor.out","w",stdout); l=read(),n=read(),m=read(); for(int i=1;i<=n;i++)//插入 { scanf("%s",S[i]); insert(i); } scanf("%s",T); int u=0; for(int i=0;i<l;i++) { int x=T[i]-'a'; u=tree[u].ch[x]; for(int j=1;j<=n;j++) if(u==pos[j]) { printf("%d\n",i-m+2); fg=1; break; } if(fg) break; } if(!fg) printf("no\n"); return 0; } /* 11 3 3 aba cba abc aaabbabzabz 14 3 4 abac ccde abcd ababccdefabcdg */
lab
Description
沿著著曲率驅動的思路,\(R\) 君開發出了時間旅行傳送門。
\(R\) 君將 \(n-1\) 個時間旅行傳送門部署到了 \(n\) 個星球。如果只走這 \(n-1\) 個時間旅行傳送門,\(R\) 君發現這 \(n\) 個星球是兩兩可達的(也就是一棵樹)。
但是時間旅行傳送門除了傳送的功能外還額外有著時間旅行的功能,比如說 \((X_i, Y_i, T_i)\) 這個傳送門,通過這個傳送門從 $X_i $到 \(Y_i\) 時間就會增加\(T_i\)(\(T_i\) 可正可負),通過這個傳送門從 \(Y_i\) 到 \(X_i\) 時間就會減少 \(T_i\)
(\(T_i\) 可正可負)。現在 \(R\) 君關心的問題是從 \(x\) 星球能不能通往 \(y\) 星球,同時時間恰好增加 \(z\)(\(z\) 可正可負)。
由於現在是一個樹形的結構,所以實際上兩點之間的路徑唯一,所以 \(R\)君很快寫了個程式計算出了這個結果。
但是隨著 \(R\) 君繼續部署傳送門,這個問題變得複雜了起來,所以請你來幫幫忙。
各種情況分析,由於路徑權值的相反性,只要有環,要麼不走,要麼等效完整走整數遍。假設有 \(k\) 個環,每個環的邊權和為 \(x_i\),那麼問題轉化為不定方程\(x\times 1+b\times x2+c\times x3+....+m\times xk=T\) 是否存在整數解。
根據不定方程整數解的條件可知,gcd(x1~xm) | T 時有,否則無。
/*
* @Author: smyslenny
* @Date: 2021.08.
* @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=1e3+5;
int n,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,w,net;
}edge[M<<1];
int head[M],num;
void addedge(int u,int v,int w)
{
edge[++num].u=u;
edge[num].v=v;
edge[num].w=w;
edge[num].net=head[u];
head[u]=num;
}
int f[M],sum[M];
void dfs_1(int u,int fa)
{
f[u]=fa;
for(int i=head[u];i;i=edge[i].net)
{
int v=edge[i].v;
if(v==fa) continue;
dfs_1(v,u);
}
}
int dis,fg;
bool dfs(int u,int fa,int t,int W)
{
for(int i=head[u];i;i=edge[i].net)
{
int v=edge[i].v;
if(v==fa) continue;//later fix it
dis+=edge[i].w;
if(v==t && dis==W) {fg=1;return true;}
else if(v==t) return false;
else
{
dfs(v,u,t,W),dis-=edge[i].w;
if(fg==1) return true;
return false;
}
}
}
int main()
{
freopen("lab.in","r",stdin);
freopen("lab.out","w",stdout);
n=read(),q=read();
for(int i=1,u,v,w;i<n;i++)
{
u=read(),v=read(),w=read();
addedge(u,v,w);
addedge(v,u,-w);
}
dfs_1(1,0);
while(q--)
{
int op=read(),u=read(),v=read(),w=read();
if(op==0) addedge(u,v,w),addedge(v,u,-w);
if(op==1) if(dfs(u,f[u],v,w)) printf("yes\n");else printf("no\n");
}
return 0;
}
/*
5 3
1 2 1
2 3 1
3 4 1
4 5 2
1 1 5 5
1 2 5 5
1 1 5 10
*/
civilization
Description
\(R\) 君在繼續著宇宙社會學的研究,\(R\) 君發現是否為善意的文明與他們的距離到本文明的距離的奇偶有很大的關係。
所以 \(R\) 君提出瞭如下簡化的問題,考慮 \(n\) 個節點帶邊權的樹,兩點間距離是兩點間樹上路徑的邊權和。
\(R\) 君想知道對於一個點來說,到這個點是距離奇數的節點的距離和,與到這個點距離是偶數的節點的距離和。
Solution
直接暴力騙分,然後我的讀入讀出檔案寫成了
freopen("civilization","r",stdin);
成功暴斃。
換根 dp
初始:
設 \(fu,0/1\) , \(fu,0/1\) 表示以 \(u\) 為根的子樹中 到 \(u\) 點距離為 偶數/奇數 的點的距離和,轉移考慮 \(w_{u,v}\) 的奇偶性 同時需要維護到 \(u\) 點距離為 偶數/奇數 的點的數量
換根:
\(fu,v\) 表示到 \(u\) 點距離為 偶數/奇數 的點的距離和
同樣轉移考慮 \(w_{u,v}\) 的奇偶性此時仍然需要動態的維護全樹中到當前根節點距離為 偶數/奇數 的點的個數。(複製的BS的,程式碼看的吳清月dalao的%%%)
Code
/*
* @Author: smyslenny
* @Date: 2021.08.
* @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;
int n,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;
}
namespace substack1{
const int M=1e3+5;
int dis[M][M];
void main()
{
memset(dis,63,sizeof(dis));
for(int i=1;i<=n;i++) dis[i][i]=0;
for(int i=1,u,v,w;i<n;i++)
{
u=read(),v=read(),w=read();
dis[u][v]=w;
dis[v][u]=w;
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
while(q--)
{
int x=read();
int js=0,os=0;
for(int i=1;i<=n;i++)
{
if(i==x) continue;
dis[i][x]%2?js+=dis[i][x]:os+=dis[i][x];
}
printf("%d %d\n",js,os);
}
}
}
namespace substack2{
const int M=1e5+5;
struct ed{
int u,v,w,net;
}edge[M<<1];
int head[M],num;
void addedge(int u,int v,int w)
{
edge[++num].u=u;
edge[num].v=v;
edge[num].w=w;
edge[num].net=head[u];
head[u]=num;
}
int num_1[M],num_2[M],dis[M],dis_1[M],dis_2[M],num_1_re[M],num_2_re[M],dis_1_re[M],dis_2_re[M],f[M];
void dfs1(int u)
{
num_1[u]++;
for(int i=head[u];i;i=edge[i].net)
{
int v=edge[i].v;
if(v==f[u])continue;
f[v]=u;
dis[v]=edge[i].w;
dfs1(v);
if(dis[v]&1)
{
dis_1[u]+=dis_2[v]+num_2[v]*dis[v];
dis_2[u]+=dis_1[v]+num_1[v]*dis[v];
num_1[u]+=num_2[v];
num_2[u]+=num_1[v];
}
else
{
dis_1[u]+=dis_1[v]+num_1[v]*dis[v];
dis_2[u]+=dis_2[v]+num_2[v]*dis[v];
num_1[u]+=num_1[v];
num_2[u]+=num_2[v];
}
}
}
void dfs2(int u)
{
if(dis[u]&1)
{
dis_1_re[u]+=dis_2_re[f[u]]+num_2_re[f[u]]*dis[u];
dis_1_re[u]+=dis_2[f[u]]-dis_1[u]-num_1[u]*dis[u]+(num_2[f[u]]-num_1[u])*dis[u];
dis_2_re[u]+=dis_1_re[f[u]]+num_1_re[f[u]]*dis[u];
dis_2_re[u]+=dis_1[f[u]]-dis_2[u]-num_2[u]*dis[u]+(num_1[f[u]]-num_2[u])*dis[u];
num_1_re[u]+=num_2_re[f[u]]+num_2[f[u]]-num_1[u];
num_2_re[u]+=num_1_re[f[u]]+num_1[f[u]]-num_2[u];
}
else
{
dis_1_re[u]+=dis_1_re[f[u]]+num_1_re[f[u]]*dis[u];
dis_1_re[u]+=dis_1[f[u]]-dis_1[u]-num_1[u]*dis[u]+(num_1[f[u]]-num_1[u])*dis[u];
dis_2_re[u]+=dis_2_re[f[u]]+num_2_re[f[u]]*dis[u];
dis_2_re[u]+=dis_2[f[u]]-dis_2[u]-num_2[u]*dis[u]+(num_2[f[u]]-num_2[u])*dis[u];
num_1_re[u]+=num_1_re[f[u]]+num_1[f[u]]-num_1[u];
num_2_re[u]+=num_2_re[f[u]]+num_2[f[u]]-num_2[u];
}
for(int i=head[u];i;i=edge[i].net)
{
int v=edge[i].v;
if(v==f[u])continue;
dfs2(v);
}
}
void main()
{
for(int i=1,u,v,w;i<n;i++)
u=read(),v=read(),w=read(),addedge(u,v,w),addedge(v,u,w);
dfs1(1);
dis_1[0]=dis_1[1];dis_2[0]=dis_2[1];num_1[0]=num_1[1];num_2[0]=num_2[1];
dfs2(1);
for(int i=1,x;i<=q;i++)
x=read(),printf("%d %d\n", dis_2[x]+dis_2_re[x],dis_1[x]+dis_1_re[x]);
}
}
int main()
{
// freopen("civilization.in","r",stdin);
// freopen("civilization.out","w",stdout);
n=read(),q=read();
if(n<=100) substack1::main();
else
substack2::main();
return 0;
}
/*
4 4
1 2 1
2 3 2
2 4 3
1
2
3
4
*/
本欲起身離紅塵,奈何影子落人間。