比赛链接
19点02分时发现比赛开始了,在纠结要不要打,如果打的话就亏了(狗头 过了一个小时上去看看,还是打了打hhh 除了G题没怎么看过。。
先放代码,之后再补题解和简单的题意hhh
每次可以选择一个字符修改为另一个字符,使得最终字符串呈递增排序。
动态规划
对于当前字符si,dp当前字符变为A~Z需要的最小花费
int n,dp[30],mi[30];
char s[maxn];
void solve()
{
sd(n);
sc(s+1);
rep(i,1,n)
{
rep(j,0,25)
{
if(j!=s[i]-'A')dp[j]=mi[j]+1;
else dp[j]=mi[j];
if(!j)mi[j]=dp[j];
else mi[j]=min(mi[j-1],dp[j]);
}
}
pd(mi[25]);
}
/*
状压dp嚯
*/
int n,p[20][20];
int sum[maxn][20][4],ans;
void solve()
{
memset(sum,INF,sizeof sum);
sd(n);
rep(i,1,n)rep(j,1,n)sd(p[i][j]);
rep(i,1,n)sum[(1<<(i-1))][i][0]=0;
rep(i,1,(1<<n)-1)
{
rep(j,1,n)//准备去往的下一个点
{
if(!(i&(1<<(j-1))))continue;
rep(k,1,n)//前一个点
{
if(!(i&(1<<(k-1)))||k==j)continue;
sum[i][j][0]=min(sum[i][j][0],sum[i^(1<<(j-1))][k][0]+p[k][j]);
sum[i][j][1]=min(sum[i][j][1],sum[i^(1<<(j-1))][k][0]);
sum[i][j][1]=min(sum[i][j][1],sum[i^(1<<(j-1))][k][1]+p[k][j]);
sum[i][j][2]=min(sum[i][j][2],sum[i^(1<<(j-1))][k][0]+p[k][j]*2);
sum[i][j][2]=min(sum[i][j][2],sum[i^(1<<(j-1))][k][2]+p[k][j]);
sum[i][j][3]=min(sum[i][j][3],sum[i^(1<<(j-1))][k][3]+p[k][j]);
sum[i][j][3]=min(sum[i][j][3],sum[i^(1<<(j-1))][k][2]);
sum[i][j][3]=min(sum[i][j][3],sum[i^(1<<(j-1))][k][1]+p[k][j]*2);
}
}
}
ans=1e9;
rep(i,1,n)ans=min(ans,sum[(1<<n)-1][i][3]);
pd(ans);
}
int n,dp[30],mi[30];
char s[maxn];
void solve()
{
sd(n);
sc(s+1);
rep(i,1,n)
{
rep(j,0,25)
{
dp[j]=mi[j]+abs(s[i]-'A'-j);
if(!j)mi[j]=dp[j];
else mi[j]=min(mi[j-1],dp[j]);
}
}
pd(mi[25]);
}
给一个n*n矩阵,从每行选一个数,共n^n种结果,要求输出前n大的和。
(输出结果得从大到小排序。。。
对于第i行,从前i-1行得到的前n大和求和,每次只要求n大的和。
int n,a[maxn][maxn];
int sum[maxn];
priority_queue<int,deque<int>,greater<int> >pq;
void solve()
{
sd(n);
rep(i,1,n)rep(j,1,n)sd(a[i][j]);
rep(i,1,n)sum[i]=a[1][i];
sort(sum+1,sum+1+n);
rep(i,2,n)
{
sort(a[i]+1,a[i]+1+n);
dep(j,n,1)dep(k,n,1)
{
if(pq.size()>=n&&sum[j]+a[i][k]<pq.top())break;
pq.push(sum[j]+a[i][k]);
while(pq.size()>n)pq.pop();
}
rep(j,1,n)sum[j]=pq.top(),pq.pop();
}
dep(i,n,1)pdk(sum[i]);
puts("");
}
第一种操作的结果:矩阵上下翻转,左右翻转。
第二种操作的结果:矩阵上下翻转。
int n,a[maxn][maxn];
int cnt1,cnt2;
void solve()
{
sd(n);
rep(i,1,n)rep(j,1,n)sd(a[i][j]);
int q;
sd(q);
while(q--)
{
int x;
sd(x);
if(x==1)cnt1^=1,cnt2^=1;
else cnt2^=1;
}
if(cnt1)
{
rep(i,1,n)
{
rep(j,1,n/2)swap(a[i][j],a[i][n-j+1]);
}
}
if(cnt2)
{
dep(i,n,1)
{
rep(j,1,n)pdk(a[i][j]);
puts("");
}
}
else
{
rep(i,1,n)
{
rep(j,1,n)pdk(a[i][j]);
puts("");
}
}
}
给一个长度为n的数组,要求找到最小的区间[l,r],区间内的和大于等于x,输出最小的l和r。
二分长度
int n,x,a[maxn];
int ansl,ansr;
bool check(int len)
{
ll sum=0;
rep(i,1,len)sum+=a[i];
if(sum>=x)
{
ansl=1;ansr=len;
return 1;
}
rep(i,len+1,n)
{
sum-=a[i-len];
sum+=a[i];
if(sum>=x)
{
ansl=i-len+1;
ansr=i;
return 1;
}
}
return 0;
}
void solve()
{
sdd(n,x);
rep(i,1,n)sd(a[i]);
int l=1,r=n;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid))r=mid-1;
else l=mid+1;
}
pdd(ansl,ansr);
}
k有限序列:
k=3时:…abbbabbbabbba…
每k+1个一队
/*
一开始还以为k没给呢qwq
*/
int n,k,c,mi,M[maxn],cnt[maxn];
ll sum[maxn],ans,SUM;
void solve()
{
mi=2e9;
ans=1e18;
sdd(n,k);k++;
rep(i,0,k)M[i]=2e9;
rep(i,1,n)
{
sd(c);
SUM+=c;
mi=min(mi,c);
sum[i%k]+=c;
M[i%k]=min(M[i%k],c);
cnt[i%k]++;
}
rep(i,0,k-1)
{
ll tmp=(SUM-sum[i])-1ll*mi*(n-cnt[i]);
tmp+=sum[i]-1ll*M[i]*cnt[i];
ans=min(ans,tmp);
}
plld(ans);
}