UPC第44场
D: Landscaping
Farmer John is building a nicely-landscaped garden, and needs to move a large amount of dirt in the process.
The garden consists of a sequence of N flowerbeds (1 <= N <= 100), where flowerbed i initially contains A_i units of dirt. Farmer John would like to re-landscape the garden so that each flowerbed i instead contains B_i units of dirt. The A_i’s and B_i’s are all integers in the range 0…10.
To landscape the garden, Farmer John has several options: he can purchase one unit of dirt and place it in a flowerbed of his choice for $X. He can remove one unit of dirt from a flowerbed of his choice and have it shipped away for $Y. He can also transport one unit of dirt from flowerbed i to flowerbed j at a cost of $Z times |i-j|. Please compute the minimum total cost for Farmer John to complete his landscaping project.
Farmer John 打算修建一座花园,他需要移动不少泥土。
花园由 N 个花坛组成(1<=N<=100),其中花坛 i包含 A_i单位的泥土。FJ 希望花坛 i包含 B_i单位的泥土,
为了达到这个目标,他可以做这几件事情:
- 购买一单位的泥土,放在指定的花坛中,费用为 X。
- 从任意一个花坛中移走一单位泥土,费用为 Y。
- 从花坛 i 运送一单位泥土到花坛 j,费用为 Z[i-j]。
请你帮 FJ 计算移动泥土的最小开销。
输入
* Line 1: Space-separated integers N, X, Y, and Z (0 <= X, Y, Z <= 1000).
* Lines 2…1+N: Line i+1 contains the space-separated integers A_i and B_i.
输出
* Line 1: A single integer giving the minimum cost for Farmer John’s landscaping project.
样例输入
4 100 200 1
1 4
2 3
3 2
4 0
样例输出
210
DP题,USACO的题解给的很巧,把这个题通过一些手段变成了编辑字符问题。以样列为例,我们可以把a数组变成 a 1 a^1 a1:1 2 2 3 3 3 4 4 4 4,目标数组b{4,3,2,0}可以变为: b 1 b^1 b1:1 1 1 1 2 2 2 3 3,问题变成了 a 1 − > b 1 a^1 ->b^1 a1−>b1的问题。我们可以定义 f [ i ] [ j ] f[i][j] f[i][j]为a的前i位变成b的前j位的操作数(用i个泥土构造j个泥土), f [ i ] [ j ] 显 然 可 以 由 f [ i − 1 ] [ j ] , f [ i ] [ j − 1 ] , f [ i − 1 ] [ j − 1 ] f[i][j]显然可以由f[i-1][j],f[i][j-1],f[i-1][j-1] f[i][j]显然可以由f[i−1][j],f[i][j−1],f[i−1][j−1]变来。
- 从 f [ i − 1 ] [ j ] f[i-1][j] f[i−1][j]推得:说白了就是把第i个废了,满足i-1个就能凑出来j个
- 从 f [ i ] [ j − 1 ] f[i][j-1] f[i][j−1] 推得:后面加上第j个,or理解为把b数组第j个废掉。
- 从 f [ i − 1 ] [ j − 1 ] f[i-1][j-1] f[i−1][j−1] 推得:在已满足状态下花费 z*(a[i]-b[j]) 费用把一份泥土转移即可.
状态转移方程也就是: f [ i ] [ j ] = m i n ( m i n ( f [ i − 1 ] [ j ] + y , f [ i ] [ j − 1 ] + x ) , f [ i − 1 ] [ j − 1 ] + z ∗ a b s ( a [ i ] − b [ j ] ) ) ; f[i][j]=min(min(f[i-1][j]+y,f[i][j-1]+x),f[i-1][j-1]+z*abs(a[i]-b[j])); f[i][j]=min(min(f[i−1][j]+y,f[i][j−1]+x),f[i−1][j−1]+z∗abs(a[i]−b[j]));
c o d e : code: code:
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<cstdio>
#include <vector>
#include <set>
#include<algorithm>
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=4500,mod = 998244353;
int a[maxn],b[maxn],la,lb,f[maxn][maxn];
int n,m,ans=0x3f3f3f3f,x,y,z,xx,yy;
int main()
{
cin >> n >> x >> y >>z;
for(int i=1;i<=n;i++)
{
cin >> xx >> yy;
while(xx)
{
a[++la]=i;
xx--;
}
while(yy)
{
b[++lb]=i;
yy--;
}
}
for(int i=1;i<=la;i++)
{
f[i][0]=i*y;
}
for(int j=1;j<=lb;j++)
{
f[0][j]=x*j;
}
for(int i=1;i<=la;i++)
{
for(int j=1;j<=lb;j++)
{
f[i][j]=min(min(f[i-1][j]+y,f[i][j-1]+x),f[i-1][j-1]+z*abs(a[i]-b[j]));
}
}
cout << f[la][lb];
return 0;
}
E: Multiple of 2019
Given is a string S consisting of digits from 1 through 9.
Find the number of pairs of integers (i,j) (1≤i≤j≤|S|) that satisfy the following condition:
Condition: In base ten, the i-th through j-th characters of S form an integer that is a multiple of 2019.
给你一个字符串,要你找到一些子区间使得s[l,r]的在十进制下的值 mod 2019 = 0,现在问你有多少这样的子区间。
Constraints
·1≤|S|≤200000
·S is a string consisting of digits from 1 through 9.
输入
Input is given from Standard Input in the following format:
S
输出
Print the number of pairs of integers (i,j) (1≤i≤j≤|S|) that satisfy the condition.
样例输入
【样例1】
1817181712114
【样例2】
14282668646
【样例3】
2119
样例输出
【样例1】
3
【样例2】
2
【样例3】
0
老问题了, s [ l , r ] s[l,r]%p=0 s[l,r] %p=0 s[l,n]%p==s[r,n]%p,如果我们需要找到同余下相同的数。并且是s[l,n]找s[r,n],其中r >= l,所以我们可以从后面往前面求。
c o d e : code: code:
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<cstdio>
#include <vector>
#include <set>
#include<algorithm>
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100005,mod = 998244353;
map<int,int>mp;
int main()
{
string s;
cin >> s;
int ans=0,sum=0;
mp[0]=1;
int k=1;
for(int i=s.length()-1;i>=0;i--)
{
ans=(ans+(s[i]-'0')*k)%2019;
sum+=mp[ans]++;
k=k*10%2019;
}
cout << sum << endl;
}
K: Cows in a Skyscraper
A little known fact about Bessie and friends is that they love stair climbing races. A better known fact is that cows really don’t like going down stairs. So after the cows finish racing to the top of their favorite skyscraper, they had a problem. Refusing to climb back down using the stairs, the cows are forced to use the elevator in order to get back to the ground floor.
The elevator has a maximum weight capacity of W (1 <= W <= 100,000,000) pounds and cow i weighs C_i (1 <= C_i <= W) pounds. Please help Bessie figure out how to get all the N (1 <= N <= 18) of the cows to the ground floor using the least number of elevator rides. The sum of the weights of the cows on each elevator ride must be no larger than W.
给出n个物品,体积为w[i],现把其分成若干组,要求每组总体积<=W,问最小分组。(n<=18)
输入
* Line 1: N and W separated by a space.
* Lines 2…1+N: Line i+1 contains the integer C_i, giving the weight of one of the cows.
输出
* Line 1: A single integer, R, indicating the minimum number of elevator rides needed.
* Lines 2…1+R: Each line describes the set of cows taking one of the R trips down the elevator. Each line starts with an integer giving the number of cows in the set, followed by the indices of the individual cows in the set.
样例输入
4 10
5
6
3
7
样例输出
3
2 1 3
1 2
1 4
应该是状压DP裸题,但是吧,我并不会。考虑dfs爆搜,由于N<=18,所以直接枚举电梯数去dfs判断可行即可,至于怎末存储具体分组,看代码。
c o d e : code: code:
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<cstdio>
#include <vector>
#include <set>
#include<algorithm>
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=45,mod = 998244353;
int c[maxn];
int n,m,ans=0x3f3f3f3f;
struct node // l存每个组的大小,a1数组存这个组有哪些,sum存这组的重量
{
int l=0;
int a1[maxn];
int sum=0;
}v[maxn];
int dfs(int x,int num) // x表示第x个物品,num表示分组数
{
for(int i=1;i<=x&&i<=num;i++) //枚举所有组。
{
if(v[i].sum+c[x]<=m) //这组可以放下
{
v[i].l++;
v[i].a1[v[i].l]=x;
v[i].sum+=c[x];
if(x==n) return 1;
if(dfs(x+1,num)) return 1;
v[i].l--; //回溯
v[i].sum-=c[x];
}
}
return 0;
}
int main()
{
cin >> n >> m;
for(int i=1;i<=n;i++)
{
cin >> c[i];
}
int i;
for(i=1;i<=n;i++)
{
memset(v,0,sizeof(v));//每次都要把该数组初始化。
if(dfs(1,i))
{
break;
}
}
cout << i << endl;
for(int j=1;j<=i;j++)
{
cout << v[j].l << " ";
for(int k=1;k<=v[j].l;k++)
{
cout << v[j].a1[k] << " ";
}
cout << endl;
}
return 0;
}