目录
- Solutions
- F. Forest Program
- I. Invoker
- J. MUV LUV EXTRA
Solutions
F. Forest Program
题意:
思路:
dfs+栈 判环
设图中环的大小分别为 \(c_1\) \(c_2\), ..., \(c_k\),不属于任何一个环的边数为 \(b\),则答案为:
\(2^b*\prod _{i=1}^{k}{(2^{c_i}-1)}\)
dfs 判环时 各点入栈 若点已存在于栈中 则存在环 计算环大小即可 不必出栈
跑一遍连通图即可计算出所有环
代码:
[]
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=3e6+5;
const int mod=998244353;
vector<int>edge[maxn];
int vis[maxn],ins[maxn],s[maxn];
int top;
int n,m;
ll ans;
void init()
{
ans=1;
memset(vis,0,sizeof vis);
memset(ins,0,sizeof ins);
for(int i=1;i<=n;i++) edge[i].clear();
top=0;
}
ll qPow(ll n,int a)
{
ll res=1;
while(a)
{
if(a&1) res=res*n%mod;
n=n*n%mod;
a>>=1;
}
return res;
}
void dfs(int u,int pre)
{
s[++top]=u;
ins[u]=1;
vis[u]=1;
for(auto x:edge[u])
{
if(!vis[x]) dfs(x,u);
else if(ins[x]&&x!=pre)
{
int t=top;
int sum=1;
while(s[t]!=x)
{
t--;
sum++;
}
m-=sum;
ans=ans*(qPow(2,sum)-1+mod)%mod;
}
}
ins[s[top]]=0;
top--;
}
int main()
{
int a,b;
while(~scanf("%d%d",&n,&m))
{
init();
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
edge[a].push_back(b);
edge[b].push_back(a);
}
for(int i=1;i<=n;i++)
if(!vis[i])
dfs(i,i);
printf("%lld\n",ans*qPow(2,m)%mod);
}
return 0;
}
I. Invoker
题意:
思路:
dp
一个 special skill 最多有 \(6\) 种排列
将前后两个技能进行 \(36\) 种排列配对
\(dp[i][j]\)( \(i\) 为第 \(i\) 个技能, \(j\) 为技能 \(i\) 的第 \(j\) 种排列)
\(dp[i][j]=min(dp[i][j],dp[i-1][k]+cmp(s[i-1]_{k},s[i]_j)(0\le j,k\le 5))\)
代码:
[]
#include<bits/stdc++.h>
using namespace std;
char s[100001];
map<char,int>mp;
char p[10][6][4]={
"QWE","QEW","WQE","WEQ","EQW","EWQ",
"WWW","WWW","WWW","WWW","WWW","WWW",
"WEE","WEE","EWE","EEW","EWE","EEW",
"QEE","QEE","EQE","EEQ","EQE","EEQ",
"QQE","QEQ","QQE","QEQ","EQQ","EQQ",
"EEE","EEE","EEE","EEE","EEE","EEE",
"QQW","QWQ","QQW","QWQ","WQQ","WQQ",
"QWW","QWW","WQW","WWQ","WQW","WWQ",
"QQQ","QQQ","QQQ","QQQ","QQQ","QQQ",
"WWE","WEW","WWE","WEW","EWW","EWW",
};
int dp[100001][6];
int cmp(int a,int b,int c,int d)
{
if(!strcmp(p[a][b],p[c][d])) return 0;
else if(p[a][b][1]==p[c][d][0]&&p[a][b][2]==p[c][d][1]) return 1;
else if(p[a][b][2]==p[c][d][0]) return 2;
return 3;
}
int main()
{
mp['B']=0,mp['C']=1,mp['D']=2,mp['F']=3,mp['G']=4,mp['T']=5,mp['V']=6,mp['X']=7,mp['Y']=8,mp['Z']=9;
while(~scanf("%s",s))
{
for(int i=0;s[i];i++)
for(int j=0;j<6;j++)
dp[i][j]=(i+1)*3+i+1;
for(int i=0;i<6;i++) dp[0][i]=3;
for(int i=1;s[i];i++)
for(int j=0;j<6;j++)
for(int k=0;k<6;k++)
dp[i][j]=min(dp[i][j],dp[i-1][k]+cmp(mp[s[i-1]],k,mp[s[i]],j));
int minn=0x3f3f3f3f;
for(int i=0;i<6;i++) minn=min(minn,dp[strlen(s)-1][i]);
printf("%d\n",minn+strlen(s));
}
return 0;
}
J. MUV LUV EXTRA
题意:
思路:
kmp
求小数部分后 \(k\) 位的真前后缀 倒着 kmp 就好
代码:
[]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+5;
char s[N];
ll nxt[N];
int len;
void getNext()
{
int i=0;
int j=-1;
nxt[0]=-1;
while(i<len)
{
if(j==-1||s[i]==s[j])
{
i++,j++;
nxt[i]=j;
}
else j=nxt[j];
}
}
int main()
{
int a,b;
while(~scanf("%lld%lld",&a,&b))
{
scanf("%s",s);
sscanf(s,"%*[^.].%s",s);
len=strlen(s);
reverse(s,s+len);
getNext();
ll ans=a-b;
for(ll i=2;i<=len;i++) ans=max(ans,a*i-b*(i-nxt[i]));
printf("%lld\n",ans);
}
return 0;
}
原文地址:https://www.cnblogs.com/c4Lnn/p/12320955.html
时间: 2024-11-04 04:42:55