http://codeforces.com/contest/544
A. Set of Strings
把一个串分成n个子串,要求这几个子串的第一个字母互不相同
#include <bits/stdc++.h>
using namespace std;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.cpp","r",stdin);
#endif // ONLINE_JUDGE
int n;
cin>>n;
string s;
cin>>s;
int cnt=1;
string a[28];
bool vis[28]={0};
int l=s.length();
a[1]+=s[0];
vis[s[0]-'a']=1;
for(int i=1;i<l;++i){
if(s[i]!=s[i-1]&&cnt<n&&!vis[s[i]-'a']){
vis[s[i]-'a']=1;
a[++cnt]+=s[i];
}else{
a[cnt]+=s[i];
}
}
if(cnt<n) puts("NO");
else{
puts("YES");
for(int i=1;i<=n;++i){
cout<<a[i]<<endl;
}
}
return 0;
}
B. Sea and Islands
S表示水,L表示沙子
在一个n*n的地图上填充m个小岛,输出一种合法解
注意奇数的情况,最多可以填充(n*n+1)/2个小岛
#include <bits/stdc++.h>
const int MAXN = 110;
using namespace std;
char mp[MAXN][MAXN];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.cpp","r",stdin);
#endif // ONLINE_JUDGE
int n,m;
scanf("%d%d",&n,&m);
if(m> ((n&1)? (n*n+1)/2 :(n*n/2) ) ) puts("NO");
else{
puts("YES");
int k=0;
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
if((i+j)%2==0&&k<m){
mp[i][j]='L';
k++;
}else{
mp[i][j]='S';
}
}
}
for(int i=0;i<n;++i){
printf("%s\n",mp[i]);
}
}
return 0;
}
C. Writing Code
n个程序猿一起完成m段代码,每个程序猿写一行代码产生的bug数为ai,求为使总bug数为b的方案数,程序猿敲代码必须是按顺序的
完全背包dp[j][k] 表示前j行代码产生k个bug的方案数,用LL
#include <bits/stdc++.h>
typedef long long LL;
const int MAXN = 510;
using namespace std;
int a[MAXN];
int n,m,b,mod;
LL dp[MAXN][MAXN];
int main()
{
scanf("%d%d%d%d",&n,&m,&b,&mod);
for(int i=0;i<n;++i){
scanf("%d",&a[i]);
}
dp[0][0]=1;
for(int i=0;i<n;++i){
for(int j=1;j<=m;++j){
for(int k=a[i];k<=b;++k){
dp[j][k]+=dp[j-1][k-a[i]];
dp[j][k]%=mod;
}
}
}
LL res=0;
for(int i=0;i<=b;++i){
res+=dp[m][i];
res%=mod;
}
cout<<res<<endl;
return 0;
}
D. Destroying Roads
一个n个顶点m条边组成的无向图。
求令s1到t1的距离不超过d1,令s2到t2的距离不超过d2. 所能删除的最多的边数
求s1到t1的最短路,s2到t2的最短路
1.s1到t1的路线与s2到t2的路线不相交
2.路线相交,那么枚举相交区间的左右端点 ,类似 H型
#include <bits/stdc++.h>
const int MAXN = 3010;
using namespace std;
vector<int> edge[MAXN];
bool vis[MAXN];
int d[MAXN][MAXN];
int n,m;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.cpp","r",stdin);
#endif // ONLINE_JUDGE
int u,v;
int s1,t1,d1,s2,t2,d2;
scanf("%d%d",&n,&m);
for(int i=0;i<m;++i){
scanf("%d%d",&u,&v);
edge[u].push_back(v);
edge[v].push_back(u);
}
queue<int> q;
for(int i=1;i<=n;++i){
memset(vis,0,sizeof(vis));
while(!q.empty()) q.pop();
q.push(i);
vis[i]=1;
d[i][i]=0;
while(!q.empty()){
u=q.front();q.pop();
for(int j=0;j<edge[u].size();++j){
v=edge[u][j];
if(!vis[v]){
vis[v]=1;
d[i][v]=d[i][u]+1;
q.push(v);
}
}
}
}
scanf("%d%d%d %d%d%d",&s1,&t1,&d1,&s2,&t2,&d2);
if(d[s1][t1]>d1||d[s2][t2]>d2){
puts("-1");
return 0;
}
int ans=d[s1][t1]+d[s2][t2];
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(d[s1][i]+d[i][j]+d[j][t1]<=d1&&d[s2][i]+d[i][j]+d[j][t2]<=d2)
ans=min(ans,d[s1][i]+d[i][j]+d[j][t1]+d[s2][i]+d[j][t2]);
if(d[s1][i]+d[i][j]+d[j][t1]<=d1&&d[t2][i]+d[i][j]+d[j][s2]<=d2)
ans=min(ans,d[s1][i]+d[i][j]+d[j][t1]+d[t2][i]+d[j][s2]);
}
}
cout<<m-ans<<endl;
return 0;
}
E. Remembering Strings
n个长度为m的字符串,替换第i个串第j个字符的花费为aij。一个串为好记的串,当且仅当存在某个位置j字母为c,使得其他串的第j个位置的字母都不为c。求使得n个字符串都为好记的串的最小花费
dp[s]表示使s好记的最小花费
两种决策
1.将第i个串的第j个位置的字母替换掉
2.替换掉这一列与c相同的字母,保留花费最大的那一个