A. k-String
简单题,不解释,统计每个字母出现的次数之后YY即可
B. Special Offer! Super Price 999 Bourles!
YY题,枚举末尾9的出现次数,然后找到出现这么多9且小于n的最大数,然后判断他们两数之差是否小于等于d即可。
代码很挫
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int digit[30];
int next[30];
int a[30];
int b[30];
int up;
long long Change(int *p)
{
// printf("%d\n",up);
int n=up,i;
__int64 ret=0;
for (i=0;i<n;i++)
{
ret=ret*10+p[i];
}
return ret;
}
int main()
{
int t,i,tag,j,ok;
__int64 n,m,k,x,y,d;
scanf("%I64d%I64d",&n,&d);
t=0;
m=n;
up=0;
while(m)
{
a[up++]=m%10;
m/=10;
}
for (i=0;i<up/2;i++)
{
t=a[i];
a[i]=a[up-i-1];
a[up-i-1]=t;
}
for (i=up;i>=0;i--)
{
ok=0;
for (j=up-1;j>up-i-1;j--)
{
b[j]=9;
if (b[j]>a[j]) ok=1;
}
for (j=up-i-1;j>=0;j--)
{
if (ok==1)
{
if (a[j]==0) b[j]=9;
else
{
b[j]=a[j]-1;
ok=0;
}
}
else
{
b[j]=a[j];
}
}
for (j=0;j<up;j++)
{
if (a[j]>b[j]) break;
if (a[j]<b[j]) break;
}
if (j!=up && a[j]<b[j]) continue;
x=Change(b);
y=Change(a);
if (y-x>d) continue;
t=0;
while(b[t]==0) {t++;}
for (j=t;j<up;j++)
{
printf("%d",b[j]);
}
printf("\n");
break;
}
return 0;
}
C.简单dp。
dp[i][j]表示排到第i个,该位置颜色为j的最小替换次数,然后就是简单的状态转移再加记录路径。
代码
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define INF 1000000000
int dp[500005][30];
char str[500005];
char ans[500005];
int main()
{
int i,j,n,k,m,tag,s;
scanf("%d%d",&n,&m);
scanf("%s",str);
for (i=0;i<n;i++)
{
for (j=0;j<m;j++)
{
dp[i][j]=INF;
}
}
for (i=0;i<m;i++)
{
if (str[0]=='A'+i) dp[0][i]=0;
else dp[0][i]=1;
}
for (i=1;i<n;i++)
{
for (j=0;j<m;j++)
{
for (k=0;k<m;k++)
{
if (j==k) continue;
if (str[i]==j+'A') dp[i][j]=min(dp[i][j],dp[i-1][k]);
else dp[i][j]=min(dp[i][j],dp[i-1][k]+1);
}
}
}
tag=-1;
s=INF;
for (i=0;i<m;i++)
{
if (s>dp[n-1][i])
{
s=dp[n-1][i];
tag=i;
}
}
printf("%d\n",s);
for (i=n-1;i>0;i--)
{
ans[i]=tag+'A';
for (j=0;j<m;j++)
{
if (j==tag) continue;
if (str[i]!=tag+'A' && dp[i][tag]==dp[i-1][j]+1 || str[i]==tag+'A' && dp[i][tag]==dp[i-1][j])
{
tag=j;
break;
}
}
}
ans[i]=tag+'A';
for (i=0;i<n;i++)
{
printf("%c",ans[i]);
}
printf("\n");
return 0;
}
D.树形dp。
扫两遍,第一遍求出dp[i],表示通过翻转边使得i能达到以i为根节点的子树上的所有节点的翻转次数。
第二遍求出ans[i],表示从i点出发能到达所有点的翻转次数。
假设父节点为last,子节点为t,那么假设已知父节点的ans[last],那么ans[t]=ans[last]+delta
其中delta表示如果存在的边是last->t,那么在ans[last]时就已经多加了个1,所以要减去1.
如果存在的边是t->last,表示ans[last]在这条边上是没有加1的,所以要加上1.
代码
#include <stdio.h>
#include <string.h>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
typedef struct Point
{
int x,y;
bool operator<(const Point &other) const
{
if (x!=other.x) return x<other.x;
return y<other.y;
}
};
int dp[510005];
vector <int> p[510005];
map <Point,int> m;
int ans[510005];
void DFS1(int t,int last)
{
int i,j,k;
Point tag;
dp[t]=0;
for (i=0;i<p[t].size();i++)
{
k=p[t][i];
if (k==last) continue;
DFS1(k,t);
tag.x=t;
tag.y=k;
dp[t]+=dp[k]+m[tag];
}
}
void DFS2(int t,int last)
{
int i,j,k;
Point tag;
tag.x=last;
tag.y=t;
if (last==-1) ans[t]=dp[t];
else
{
if (m[tag]==0) ans[t]=ans[last]+1;
else ans[t]=ans[last]-1;
}
for (i=0;i<p[t].size();i++)
{
k=p[t][i];
if (k==last) continue;
DFS2(k,t);
}
}
int main()
{
int i,j,n,x,y,ok,s;
Point tag;
scanf("%d",&n);
for (i=0;i<n-1;i++)
{
scanf("%d%d",&x,&y);
p[x].push_back(y);
p[y].push_back(x);
tag.x=y;
tag.y=x;
m[tag]=1;
}
DFS1(1,-1);
DFS2(1,-1);
s=100000005;
for (i=1;i<=n;i++)
{
s=min(s,ans[i]);
}
printf("%d\n",s);
ok=0;
for (i=1;i<=n;i++)
{
if (ok==0 && s==ans[i])
{
printf("%d",i);
ok=1;
}
else if (s==ans[i])
{
printf(" %d",i);
}
}
printf("\n");
}