A.Wall - AtCoder abc079_d - Virtual Judge
题意有点绕,我是用dfs搜一遍,走过的列自然不能重新走一遍,不然就会浪费。对所有数字用map存一下就不用重复计算了。
#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5+100;
const int mod = 998244353;
int n,m,k;
int c[10][10];
map<int,int>v;
int min1=INT_MAX;
bool hang[10],lie[10];
void dfs(int hangxx,int cost){
if(hangxx==1){
min1=min(min1,cost);
return;
}
for(int j=0;j<10;j++){
if(hang[hangxx]&&lie[j]) return;
lie[j]=1;
hang[hangxx]=1;
dfs(j,cost+c[hangxx][j]);
hang[hangxx]=0;
//lie[j]=0;
}
return;
}
void sovle(){
int sum=0;
cin>>n>>m;
int a[n][m];
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
cin>>c[i][j];
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>a[i][j];
if(a[i][j]!=1&&a[i][j]!=-1){
v[a[i][j]]++;
}
}
}
for(auto ed:v){
dfs(ed.first,0);
sum+=min1*ed.second;
min1=INT_MAX;
memset(hang,sizeof(hang),0);
memset(lie,sizeof(lie),0);
}
cout<<sum<<endl;
}
signed main()
{
ios::sync_with_stdio(false), cin.tie(0),cout.tie(0);
int t = 1;
//cin>>t;
while (t--){
sovle();
}
return 0;
}
B.C - Linear Approximation
长度为n的序列,找任意一个整数b,使abs(a[i]-(i+b))的和最小。
先将a[i]减去i,那么就是求a[i]-b的绝对值和最小.
转换模型我们可以把a[i]看成数轴上的点,那么就是要求数轴上一个点到其他点的距离最小。
假设找的点是蓝色点,向左移动d个单位,则左边点到它的距离-d,右边+d,那么-4d+2d=-2d减少了2d.
可见只要蓝点左右两边点数不同就不是最优解,那么使左右两边点数相同的就是这些点坐标的中位数了。
#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 3e5+10;
const int mod = 998244353;
int n,m,k;
void sovle(){
cin>>n;
vector<int>a(n);
for(int i=0;i<n;i++){
cin>>a[i];
a[i]-=i+1;
}
int sum=0;
sort(a.begin(),a.end());
for(int i=0;i<n;i++){
sum+=abs(a[i]-a[(n)/2]);
}
cout<<sum<<endl;
}
signed main()
{
ios::sync_with_stdio(false), cin.tie(0),cout.tie(0);
int t = 1;
//cin>>t;
while (t--){
sovle();
}
return 0;
}
C.C - Minimization
因为这是一个排列,所以最后都会变成1,故从1开始改是最优解,对于k长度的框,让1在1-k每个单位长度开始滑动,每次取min
#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 3e5+10;
const int mod = 998244353;
int n,m,k;
void sovle(){
int ii=0;
cin>>n>>k;
vector<int>a(n);
for(int i=0;i<n;i++){
cin>>a[i];
if(a[i]==1){
ii=i;
}
}
int sum=INT_MAX;
for(int i=max((ll)0,ii-k+1);i<=ii;i++){
int u=ii-i,v=k-u-1;
int num=1;
num+=(ii-u+k-2)/(k-1);
num+=(n-ii-v-1+k-2)/(k-1);
sum=min(sum,num);
}
cout<<sum<<endl;
}
signed main()
{
ios::sync_with_stdio(false), cin.tie(0),cout.tie(0);
int t = 1;
//cin>>t;
while (t--){
sovle();
}
return 0;
}
G.Problem - 1107C - Codeforces
找出每个长度大于k的连续子字符串,取出最小的多余的部分的a[i]就是答案
#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5+10;
const int mod = 998244353;
int n,m,k,sum,num;
int x,y,z;
map<pair<int,int>,int>v;
int a[N];
void sovle(){
cin>>n>>m;
for(int i=0;i<n;i++) cin>>a[i];
string s;cin>>s;
for(int i=1;i<n;i++){
if(s[i]==s[i-1]){
int begin=i-1,end;
while(i<n&&s[i]==s[i-1]){
i++;
}i--;
end=i;
if(end-begin+1>k) v[mk(begin,end)]=1;
}
}
int sum=0,num=0;
for(auto ed:v){
sort(a+ed.first.first,a+ed.first.second+1);
int u=ed.first.second-ed.first.first+1-m;
for(int i=ed.first.first;i<ed.first.first+u;i++){
sum+=a[i];
}
}
for(int i=0;i<n;i++){
num+=a[i];
}cout<<num-sum<<endl;
}
signed main()
{
ios::sync_with_stdio(false), cin.tie(0),cout.tie(0);
int t = 1;
//cin>>t;
while (t--){
sovle();
}
return 0;
}