wxy 3.31 牛客练习赛60重现

v>

wxy 3.31 牛客练习赛60重现
5075
A
看到位运算,可以往二进制方面去想,可以把1-n所有的的每位放到相应的位置上,然后遍历所有的
数,每次都把他拆分成二进制和刚刚统计的那些数的每位进行与运算
C
DP
设dp[ i ] [ j ]表示前i个,长度为j的本质不同的子序列有多少,那么dp[ i ] [ j ]=dp[ i - 1] [ j - 1 ]+dp[ i - 1]
[ j ],但是会有重复,要减去前面的 dp [ pos[ s[ i ] ] ] [ j -1 ]
然后初始化, i:0-n dp[ i ] [ 0 ]=1 选0个的宣发为1,就是什么都不选
dp考虑如何转移,如何从前一步到当前步,dp[ i ] [ j ] = dp [ i - 1 ] [ j ] + dp[ i - 1 ] [ j - 1 ]一般当前步有
两种选择,选择当前这一个或者不选择当前这一个。每多一个有可能会和前面有重复,重复部分一般是
和当前位置相同的位置。
D
数据出水了。。。用比赛时候的做法是会TLE,但是如果比赛的时候有很多人过了的题,莽一发没有关
系,T了不亏
真正的做法是同余最短路 get到新姿势
# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
const int MAXN=1e3+100;
char s[MAXN];
int pos[30],dp[MAXN][MAXN];
int main()
{
LL n,k; scanf("%lld%lld",&n,&k);
scanf("%s",s+1);
dp[0][0]=1;
for(int i=1;i<=n;++i){
dp[i][0]=1;
for(int j=1;j<=k;++j){
dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
if(pos[s[i]-'a']) dp[i][j]-=dp[pos[s[i]-'a']-1][j-1];
dp[i][j]=(dp[i][j]%mod+mod)%mod;
}
pos[s[i]-'a']=i;
}
printf("%d",dp[n][k]);
return 0;
}E
长链剖分 待补
# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int MAXN=1e5+100;
const int INF=0x7fffffff;
LL dis[MAXN];
LL ans[10];
LL a,b,c,k;
pii edge[MAXN];
void dij()
{
for(int i=1;i<=c;++i) dis[i]=INF;
priority_queue<pii,vector<pii>,greater<pii> > q;
q.push(pii(0,0));
while(!q.empty()){
pii x=q.top(); q.pop();
int u=x.first,v=x.second;
if(dis[(v+a)%c]>dis[v]+a){
dis[(v+a)%c]=dis[v]+a;
edge[(v+a)%c]=pii(v,1);
q.push(pii(dis[(v+a)%c],(v+a)%c));
}
if(dis[(v+b)%c]>dis[v]+b){
dis[(v+b)%c]=dis[v]+b;
edge[(v+b)%c]=pii(v,2);
q.push(pii(dis[(v+b)%c],(v+b)%c));
}
}
return ;
}
void dfs(LL now)
{
if(now==0) return ;
ans[edge[now].second]++;
dfs(edge[now].first);
return ;
}
int main()
{
scanf("%lld%lld%lld%lld",&a,&b,&c,&k);
dij();
dfs(k%c);
ans[3]=(k-a*ans[1]-b*ans[2])/c;
printf("%lld %lld %lld\n",ans[1],ans[2],ans[3]);
return 0;
}
posted @ 2022-02-27 13:13  fengzlj  阅读(46)  评论(0)    收藏  举报