前言
在gym看到,知道山东省很nb所以写了。
补题含大量借鉴大佬代码()
F Birthday Cake
题意:给定n个串,求有多少对串能拼出平方串(能够表示成两个相同的字符串连接在一起的,即AA)。
思路:队友想出来了,就是少考虑了一个情况。
考虑这样一个串:abcdyouareabcd。
前后缀相同。我们可以计数有多少个串youare。
这两个串可以拼接在一起。
还有一种情况就是两个串一模一样。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 4e5+5;
char s[maxn];
typedef long long ll;
// 自然溢出会被卡啊
const int mod1 = 1e9+7; // 两个模数,再弄个Pair,减少crash
const int mod2 = 998244353;
const int p = 101;
ll base1[maxn],base2[maxn];
ll hs1[maxn],hs2[maxn];
map<pair<ll,ll>,int> mp,mp2; // 计数菌
// mp用来存整串的hash, mp2用来存去掉相同前后缀后中间部分的hash
// 取子串的hash
pair<ll,ll> subs(int l,int r){
ll ans1=(hs1[r]+mod1-hs1[l-1]*base1[r-l+1]%mod1)%mod1;
ll ans2=(hs2[r]+mod2-hs2[l-1]*base2[r-l+1]%mod2)%mod2;
return make_pair(ans1,ans2);
}
int main(){
int n;scanf("%d",&n);
// 初始化处理hash
base1[0]=1;
base2[0]=1;
for(int i=1;i<=maxn;++i){
base1[i]=base1[i-1]*p%mod1;
base2[i]=base2[i-1]*p%mod2;
}
ll ans = 0;
while(n--){
scanf("%s",s+1);
int len = strlen(s+1);
hs1[0]=0;hs2[0]=0;
for(int i=1;i<=len;++i){
hs1[i] = (hs1[i-1]*p+s[i]-'a'+1)%mod1;
hs2[i] = (hs2[i-1]*p+s[i]-'a'+1)%mod2;
}
pair<ll,ll> o = make_pair(hs1[len],hs2[len]);
ans += mp[o]; // 加上跟该串一模一样的
mp[o]++;
ans += mp2[o]; // 加上内部和{该串整串}一样的串
for(int i=1;2*i<len;++i){
// 1 - i, len-i+1 - len
o = subs(1,i);
pair<ll,ll> o2 = subs(len-i+1,len);
if(o==o2){
// 前后缀一样
o = subs(i+1,len-i);
// 中间部分
ans += mp[o]; // 加上整串和该串内部一样的串
mp2[o]++;
}
}
}
printf("%lld\n",ans);
}
J Tuition Agent
题意:n个人,每个人有三个属性,rank,X和Y。要把每个人划分为老师和学生,当老师的rank小于学生的rank,可以将这老师和学生进行配对。配出一对赚k元,将i号变成老师-Xi元,变成学生-Yi元。求最后最多的钱。可能为负。数据随机生成。1e5。
思路:先用R排序(倒序)。
由于老师肯定比学生高级,因此后面放老师相对更优。
d
p
[
到
第
几
个
人
]
[
前
面
有
多
少
个
未
配
对
学
生
]
dp[到第几个人][前面有多少个未配对学生]
dp[到第几个人][前面有多少个未配对学生]
表示能得到的最多钱。
// step1:做导师
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
]
[
j
]
,
d
p
[
i
−
1
]
[
j
+
1
]
−
X
i
+
k
)
;
dp[i][j] = max(dp[i][j], dp[i-1][j+1] - Xi + k);
dp[i][j]=max(dp[i][j],dp[i−1][j+1]−Xi+k); // 配对掉一个学生
// step2:做学生
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
]
[
j
]
,
d
p
[
i
−
1
]
[
j
−
1
]
−
Y
i
)
;
dp[i][j] = max(dp[i][j], dp[i-1][j-1] - Yi);
dp[i][j]=max(dp[i][j],dp[i−1][j−1]−Yi); // 成为学生
注意到数据随机生成,猜测未配对数较小。
于是暴力跑。
后面数据好像加强了,怎么都过不了了,违背了随机生成的初心(不是)。这道题成为一道无解题。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
typedef long long ll;
const int inf = 1e9;
struct _node{
int x,y,r;
}node[maxn];
bool cmp(_node a,_node b){
return a.r<b.r;
}
ll dp[3][3003];
int main(){
int t;scanf("%d",&t);
while(t--){
int n,k;scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i){
scanf("%d%d%d",&node[i].r,&node[i].x,&node[i].y);
}
// 注意rank小的才能教rank大的
sort(node+1,node+1+n,cmp);
int m = min(min(100000000/n+1,n),502);
for(int i=1;i<=m;++i) dp[0][i]=-inf;
dp[0][0] = 0;
for(int i=1;i<=n;++i){
for(int j=0;j<=m;++j) dp[1][j]=-inf;
for(int j=0;j<=m;++j){
// 未配对的有j个
// 加入一个tut,未配对的tut就多了1
if(j<m)
dp[1][j+1]=max(dp[1][j+1],dp[0][j]-node[i].x);
// 加入一个stu,未配对的tut就减1,配对数+1
if(j)
dp[1][j-1]=max(dp[1][j-1],dp[0][j]-node[i].y+k);
else
dp[1][j]=max(dp[1][j],dp[0][j]-node[i].y);
}
for(int j=0;j<=m;++j) dp[0][j]=dp[1][j];
}
ll ans = -inf;
for(int i=0;i<=m;++i)
ans = max(dp[0][i],ans);
printf("%lld\n",ans);
}
}