2017CCPC女生赛
最近组队赛有点拉跨,于是个人vp加训,写写题解。
2021.10.13
A - Automatic Judge
签到,模拟。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+7;
const int MOD = 1e9+7;
int n,m;
int main(){
int T=1;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
vector<pair<int,int>> ve[22];
for(int i=1,a,b,c;i<=m;i++){
char d[22];
scanf("%d %d:%d %s",&a,&b,&c,d);
int t=b*60+c;
if(d[0]=='A'&&d[1]=='C'){
ve[a-1000].push_back({t,1});
}else {
ve[a-1000].push_back({t,0});
}
}
int ans=0,cnt=0;
for(int i=1;i<=n;i++){
int s=0;
sort(ve[i].begin(),ve[i].end());
for(auto j:ve[i]){
if(j.second){
cnt++;
ans+=s+j.first;
break;
}else{
s+=20;
}
}
}
printf("%d %d\n",cnt,ans);
}
}
B - Building Shops
dp。先对每个pair按照位置排序,f [ i ] [ j ] f[i][j]f[i][j]为考虑前i ii个点,上一次选在j jj时的答案,则有f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ i − 1 ] [ j ] + x [ i ] − x [ j ] ) ( i ! = j ) , f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ i − 1 ] [ j ] + c [ i ] ) ( i = = j ) f[i][j]=min(f[i][j],f[i-1][j]+x[i]-x[j])(i!=j),f[i][j]=min(f[i][j],f[i-1][j]+c[i])(i==j)f[i][j]=min(f[i][j],f[i−1][j]+x[i]−x[j])(i!=j),f[i][j]=min(f[i][j],f[i−1][j]+c[i])(i==j)。最终答案为m a x ( { f [ n ] [ 1... n ] } ) max(\{f[n][1...n]\})max({f[n][1...n]})。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3000+7;
const int MOD = 1e9+7;
int n,x[N],c[N];
ll f[N][N];
pair<int,int> p[N];
ll solve(){
sort(p+1,p+1+n);
memset(f,0x3f,sizeof f);
f[1][1]=p[1].second;
for(int i=2;i<=n;i++){
for(int j=1;j<i;j++){
f[i][j]=min(f[i][j],f[i-1][j]+p[i].first-p[j].first);
f[i][i]=min(f[i][i],f[i-1][j]+p[i].second);
}
}
return *min_element(f[n]+1,f[n]+1+n);
}
int main(){
int T=1;
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++){
scanf("%d%d",x+i,c+i);
p[i]={x[i],c[i]};
}
printf("%lld\n",solve());
}
}
C - Coprime Sequence
签到,处理出前后缀gcd \gcdgcd然后枚举删的位置。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000+7;
const int MOD = 1e9+7;
int n,a[N];
int l[N],r[N];
int main(){
int T=1;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
}
for(int i=1;i<=n;i++){
l[i]=__gcd(l[i-1],a[i]);
}
r[n+1]=0;
for(int i=n;i>=1;i--){
r[i]=__gcd(r[i+1],a[i]);
}
int ans=max(r[2],l[n-1]);
for(int i=2;i<n;i++){
ans=max(ans,__gcd(l[i-1],r[i+1]));
}
printf("%d\n",ans);
}
}
D - Deleting Edges
图论。考虑最终形成的是一棵以0为根的生成树,可以枚举最后形成的树中每个点连向父亲的那条边,对每个结点来说,删边方案是相互独立的(因为树上每个点的父亲唯一),乘起来就是最终答案。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 50+7;
const int MOD = 1e9+7;
int n,a[N][N],b[N][N];
int main(){
int T=1;
while(~scanf("%d",&n)){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%1d",&a[i][j]);
b[i][j]=a[i][j];
if(!b[i][j])b[i][j]=0x3f3f3f3f;
if(i==j)b[i][j]=0;
}
}
for(int k=0;k<n;k++)
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(b[i][k]&&b[k][j]){
b[i][j]=min(b[i][j],b[i][k]+b[k][j]);
}
}
}
ll ans=1;
for(int i=1;i<n;i++){
ll res=0;
for(int j=0;j<n;j++){
if(a[j][i]&&b[0][j]+a[j][i]==b[0][i]){
res++;
}
}
ans=ans*res%MOD;
}
printf("%lld\n",ans);
}
}
E - Easy Summation
签到,怎么做都行。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 10000+7;
const int MOD = 1e9+7;
int n,m;
ll ans[6][N];
ll qpow(ll a,ll n=MOD-2,ll m=MOD){
ll res=1;
a%=m;
while(n){
if(n&1)res=res*a%m;
a=a*a%m,n>>=1;
}
return res;
}
int main(){
for(int i=0;i<=5;i++){
for(int j=1;j<N;j++){
ans[i][j]=(ans[i][j-1]+qpow(j,i))%MOD;
}
}
int T=1;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
printf("%lld\n",ans[m][n]);
}
}
F - Forgiveness
赛中没过,待补。感觉是个O ( 10 ∗ n ∗ n ∗ log n ) O(10*n*\sqrt{n}*\log{n})O(10∗n∗n∗logn)的分块(应该没有log n \log{n}logn?)。
(后记:Claris出的防AK,据说要bitset搞搞)
G - Graph Theory
图论。考虑每个1和前面的2匹配,剩下的1两两匹配,剩下2或者n为奇数就是No。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000+7;
const int MOD = 1e9+7;
int n,a[N];
int main(){
int T=1;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
int cnt=1;
a[1]=2;
for(int i=2;i<=n;i++){
scanf("%d",a+i);
if(a[i]==1){
if(cnt>0)cnt--;
}else{
cnt++;
}
}
puts((cnt==0&&n%2==0)?"Yes":"No");
}
}
H - Happy Necklace
打表,数学。题意等价求长为n且两个0的距离大于2的01串的方案数,赛中人工打了个表(2,3,4,6,9,13),发现是f [ n ] = f [ n − 1 ] + f [ n − 3 ] f[n]=f[n-1]+f[n-3]f[n]=f[n−1]+f[n−3],矩阵快速幂即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000+7;
const int MOD = 1e9+7;
const int K=3+7;
struct mat{
int a[K][K];
mat(){memset(a,0,sizeof a);}
int* operator [] (int i){return a[i];}
mat operator * (mat b){
mat res;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
for(int k=0;k<3;k++){
(res[i][j]+=1LL*a[i][k]*b[k][j]%MOD)%=MOD;
}
}
}
return res;
}
};
mat qpow(mat a,ll n){
mat res;
for(int i=0;i<3;i++){
res.a[i][i]=1;
}
while(n){
if(n&1)res=res*a;
a=a*a,n>>=1;
}
return res;
}
ll n;
int main(){
int T=1;
scanf("%d",&T);
while(T--){
scanf("%lld",&n);
ll ans=0;
mat A,B;
A[0][0]=1;
A[0][1]=2;
A[0][2]=3;
B[2][1]=B[0][2]=B[1][0]=B[2][2]=1;
A=A*qpow(B,n-2);
printf("%d\n",A[0][2]);
}
}
I - Innumerable Ancestors
树论。结论:k kk个点中LCA深度最大的两点dfs序一定相邻(考虑反证法),所以对集合A,B按照dfs序排序并双指针处理。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000+7;
const int MOD = 1e9+7;
int n,m,k1,k2,dfn[N],tot,a[N],b[N];
int dep[N],fa[N][20];
vector<int> G[N];
void dfs(int u,int pre=0){
dep[u]=dep[pre]+1;
fa[u][0]=pre;
dfn[u]=++tot;
for(int v:G[u])
if(v!=pre)
dfs(v,u);
}
void init(int n){
for(int i=1;(1<<i)<=n;i++)
for(int j=1;j<=n;j++)
fa[j][i]=fa[fa[j][i-1]][i-1];
}
int lca(int u,int v){
if(dep[u]<dep[v])swap(u,v);
int d=dep[u]-dep[v];
for(int i=0;(1<<i)<=d;i++)
if(d&(1<<i))u=fa[u][i];
if(u==v)return u;
for(int i=17;i>=0;i--)
if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
bool cmp(int a,int b){
return dfn[a]<dfn[b];
}
int main(){
int T=1;
while(~scanf("%d%d",&n,&m)){
tot=0;
for(int i=1;i<=n;i++){
G[i].clear();
}
memset(dep,0,sizeof dep);
memset(fa,0,sizeof fa);
memset(dfn,0,sizeof dfn);
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1);
init(n);
while(m--){
scanf("%d",&k1);
for(int i=1;i<=k1;i++){
scanf("%d",a+i);
}
scanf("%d",&k2);
for(int i=1;i<=k2;i++){
scanf("%d",b+i);
}
sort(a+1,a+1+k1,cmp);
sort(b+1,b+1+k2,cmp);
int p=1,ans=0;
for(int q=1;q<=k2;q++){
while(p+1<=k1&&dfn[a[p+1]]<=dfn[b[q]]){
p++;
}
ans=max(ans,dep[lca(a[p],b[q])]);
}
p=1;
for(int q=1;q<=k2;q++){
while(p+1<=k1&&dfn[a[p]]<=dfn[b[q]]){
p++;
}
ans=max(ans,dep[lca(a[p],b[q])]);
}
printf("%d\n",ans);
}
}
}
J - Judicious Strategy
博弈,打表。直接O ( n 3 log n ) O(n^3\log n)O(n3logn)预处理出所有子串及其权值,然后打表,记录一个( w i n , A , B ) (win,A,B)(win,A,B)的三元组表示胜负状态和玩家分数,注意一个字符串中的同一个子串只算出现一次(如"aaaa"中,"aa"的出现次数为1)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 30+7;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
int n;
map<string,int> mp,w;
struct node{
int win,S[2];
};
map<string,node> f;
int getW(string s){
int sum=0,mx=0;
for(int i=0;i<s.size();i++){
mx=max(mx,s[i]-'a'+1);
sum+=s[i]-'a'+1;
}
return sum*mx+mp[s];
}
node dfs(string s,int p){
int q=1^p;
if(f.count(s))return f[s];
node res;
res.win=0;
res.S[p]=-INF;
res.S[q]=INF;
for(int i=0;i<26;i++){
string tt;
tt.push_back(char(i+'a'));
string t=tt+s;
if(mp.count(t)){
node tmp=dfs(t,q);
if(tmp.win==0){
if(tmp.S[p]==res.S[p]&&tmp.S[q]<res.S[q]||tmp.S[p]>res.S[p]){
res=tmp;
}
res.win=1;
}else if(res.win==0){
if(tmp.S[p]==res.S[p]&&tmp.S[q]<res.S[q]||tmp.S[p]>res.S[p]){
res=tmp;
}
res.win=0;
}
}
t=s+tt;
if(mp.count(t)){
node tmp=dfs(t,q);
if(tmp.win==0){
if(tmp.S[p]==res.S[p]&&tmp.S[q]<res.S[q]||tmp.S[p]>res.S[p]){
res=tmp;
}
res.win=1;
}else if(res.win==0){
if(tmp.S[p]==res.S[p]&&tmp.S[q]<res.S[q]||tmp.S[p]>res.S[p]){
res=tmp;
}
res.win=0;
}
}
}
if(res.win==0&&res.S[p]==-INF){
res.S[0]=res.S[1]=0;
}
res.S[q]+=w[s];
return f[s]=res;
}
string s[N];
void solve(){
mp.clear();
w.clear();
f.clear();
for(int i=1;i<=n;i++){
set<string> se;
for(int j=0;j<s[i].size();j++){
string tmp;
for(int k=j;k<s[i].size();k++){
tmp.push_back(s[i][k]);
se.insert(tmp);
}
}
for(auto j:se){
mp[j]++;
}
}
for(auto i:mp){
w[i.first]=getW(i.first);
}
string emp;
node res=dfs(emp,0);
if(res.win==0){
cout<<"Bob\n";
}else cout<<"Alice\n";
cout<<res.S[0]<<" "<<res.S[1]<<"\n";
}
int main(){
ios::sync_with_stdio(false);
while(cin>>n){
for(int i=1;i<=n;i++){
cin>>s[i];
}
solve();
}
}