Mikhail walks on a 2D plane. He can go either up or right. You are given a sequence of Mikhail's moves. He thinks that this sequence is too long and he wants to make it as short as possible.
In the given sequence moving up is described by character U and moving right is described by character R. Mikhail can replace any pair of consecutive moves RU or UR with a diagonal move (described as character D). After that, he can go on and do some other replacements, until there is no pair of consecutive moves RU or UR left.
Your problem is to print the minimum possible length of the sequence of moves after the replacements.
The first line of the input contains one integer n (1 ≤ n ≤ 100) — the length of the sequence. The second line contains the sequence consisting of n characters U and R.
Print the minimum possible length of the sequence of moves after all replacements are done.
5 RUURU
3
17 UUURRRRRUUURURUUU
13
In the first test the shortened sequence of moves may be DUD (its length is 3).
In the second test the shortened sequence of moves can be UUDRRRDUDDUUU (its length is 13).
水
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=100005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
char s[maxn];
int main() {
int n,i,x,y;
scanf("%d",&n);
scanf("%s",s+1);
int ans=n;
for (i=1;i<=n;i++) {
if (i!=n)
if (s[i]!=s[i+1]) ans--,i++;
}
cout << ans;
return 0;
}
You are given a string s consisting of n lowercase Latin letters. You have to type this string using your keyboard.
Initially, you have an empty string. Until you type the whole string, you may perform the following operation:
- add a character to the end of the string.
Besides, at most once you may perform one additional operation: copy the string and append it to itself.
For example, if you have to type string abcabca, you can type it in 7 operations if you type all the characters one by one. However, you can type it in 5 operations if you type the string abc first and then copy it and type the last character.
If you have to type string aaaaaaaaa, the best option is to type 4 characters one by one, then copy the string, and then type the remaining character.
Print the minimum number of operations you need to type the given string.
The first line of the input containing only one integer number n (1 ≤ n ≤ 100) — the length of the string you have to type. The second line containing the string s consisting of n lowercase Latin letters.
Print one integer number — the minimum number of operations you need to type the given string.
7 abcabca
5
8 abcdefgh
8
The first test described in the problem statement.
In the second test you can only type all the characters one by one.
同样水
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=1005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
char s[maxn];
int main() {
int n,i,j,ans=-1;
scanf("%d",&n);
scanf("%s",s+1);
for (i=1;i<=n/2;i++) {
int flag=1;
for (j=1;j<=i;j++) {
if (s[j]!=s[j+i]) flag=0;
}
if (flag) ans=i;
}
if (ans==-1) ans=n; else ans=min(n-ans+1,n);
cout << ans;
return 0;
}
注意到只能上下或左右走,而左右走时,绝对值差必为1;上下走时,绝对值差可能不为1,但一定相等,且为一行的元素数。
如此,只要判断序列中所有相邻数的绝对值差是不是只有两种可能。
一种特殊的情况:从一行末尾走到下一行开头是不合法的。这种情况需要特判。
另一组特别容易挂的数据:
3
1 2 4
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=200005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
int a[maxn];
int main() {
int n,i,j;
scanf("%d",&n);
j=-1;
for (i=1;i<=n;i++) {
scanf("%d",&a[i]);
if (i!=1) j=max(j,abs(a[i]-a[i-1]));
if (a[i]==a[i-1]&&i!=1) {
printf("NO\n");
return 0;
}
}
if (j==1) {
int ans=-1;
for (i=1;i<=n;i++) ans=max(ans,a[i]);
printf("YES\n%d 1\n",ans);return 0;
}
if (n==1) {
printf("YES\n%d 1\n",a[1]);return 0;
}
for (i=2;i<=n;i++) {
if (abs(a[i]-a[i-1])!=j&&abs(a[i]-a[i-1])!=1) {
printf("NO\n");
return 0;
}
}
for (i=2;i<=n;i++) {
if (abs(a[i]-a[i-1])==1) { //判断是否从一行结尾走到下一行开头
if (a[i]%j==0&&a[i-1]%j==1&&a[i]/j==a[i-1]/j) {
printf("NO\n");
return 0;
}
if (a[i]%j==1&&a[i-1]%j==0&&a[i]/j==a[i-1]/j) {
printf("NO\n");
return 0;
}
}
}
printf("YES\n1000000000 %d\n",j);
return 0;
}
预处理所有点到起点和终点的距离,再O(n^2)枚举所有情况。
预处理可以直接bfs,也可以使用某种最短路算法。
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=1005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
int dist[maxn],head[maxn],dis[maxn];
bool inque[maxn],f[maxn][maxn];
int num=0;
vector<int> v[maxn];
struct Edge {
int from,to,pre,dist;
};
Edge edge[maxn*2];
void addedge(int from,int to,int dist) {
edge[num]=(Edge){from,to,head[from],dist};
head[from]=num++;
edge[num]=(Edge){to,from,head[to],dist};
head[to]=num++;
}
void spfa(int s,int des){
int i;
memset(inque,0,sizeof(inque));
memset(dist,0x3f,sizeof(dist));
inque[s]=1;
queue<int> q;
q.push(s);
dist[s]=0;
while (!q.empty()) {
int now=q.front();
q.pop();
inque[now]=0;
for (i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (dist[edge[i].from]+edge[i].dist<dist[to]) {
q.push(to);
dist[to]=dist[edge[i].from]+edge[i].dist;
}
}
}
}
void spf(int s,int des){
int i;
memset(inque,0,sizeof(inque));
memset(dis,0x3f,sizeof(dis));
inque[s]=1;
queue<int> q;
q.push(s);
dis[s]=0;
while (!q.empty()) {
int now=q.front();
q.pop();
inque[now]=0;
for (i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (dis[edge[i].from]+edge[i].dist<dis[to]) {
q.push(to);
dis[to]=dis[edge[i].from]+edge[i].dist;
}
}
}
}
int main() {
int n,m,i,j,x,y,s,t;
num=0;
memset(head,-1,sizeof(head));
mem0(f);
scanf("%d%d%d%d",&n,&m,&s,&t);
for (i=1;i<=m;i++) {
scanf("%d%d",&x,&y);
addedge(x,y,1);
f[x][y]=f[y][x]=1;
}
spfa(s,t);
spf(t,s);
int ans=0;
for (i=1;i<=n;i++) {
for (j=i+1;j<=n;j++) {
if (f[i][j]) continue;
if (1+dist[i]+dis[j]>=dist[t]&&1+dist[j]+dis[i]>=dist[t]) ans++;
}
}
printf("%d\n",ans);
return 0;
}
Consider a system of n water taps all pouring water into the same container. The i-th water tap can be set to deliver any amount of water from 0 to ai ml per second (this amount may be a real number). The water delivered by i-th tap has temperature ti.
If for every you set i-th tap to deliver exactly xi ml of water per second, then the resulting temperature of water will be
(if
, then to avoid division by zero we state that the resulting water temperature is 0).
You have to set all the water taps in such a way that the resulting temperature is exactly T. What is the maximum amount of water you may get per second if its temperature has to be T?
The first line contains two integers n and T (1 ≤ n ≤ 200000, 1 ≤ T ≤ 106) — the number of water taps and the desired temperature of water, respectively.
The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 106) where ai is the maximum amount of water i-th tap can deliver per second.
The third line contains n integers t1, t2, ..., tn (1 ≤ ti ≤ 106) — the temperature of water each tap delivers.
Print the maximum possible amount of water with temperature exactly T you can get per second (if it is impossible to obtain water with such temperature, then the answer is considered to be 0).
Your answer is considered correct if its absolute or relative error doesn't exceed 10 - 6.
2 100 3 10 50 150
6.000000000000000
3 9 5 5 30 6 6 10
40.000000000000000
2 12 1 3 10 15
1.666666666666667
一个结论:我们总是能够用完比T温度高的所有龙头,或比T温度低的所有龙头。
证明:假设我们把这两半的$$\sum x_{i}(t_{i}-T)$$ 相比较,一定是一正一负。那么,绝对值少的那一部分总会被耗光,因为另一部分总能和它们中和,使得总温度为T.那么,在其中一半用光的情况下,另外一半当中一定是尽量选温度离T近的水更优,因为这时$$\sum x_{i}(t_{i}-T)$$定了,$$(t_{i}-T)$$越小,$$x_{i}$$总和就越大。
所以只要假设这两部分其中一部分用光,另一部分贪心,比较一下两种情况哪种最优就好了。
代码没写完,待补。
You are running through a rectangular field. This field can be represented as a matrix with 3 rows and mcolumns. (i, j) denotes a cell belonging to i-th row and j-th column.
You start in (2, 1) and have to end your path in (2, m). From the cell (i, j) you may advance to:
- (i - 1, j + 1) — only if i > 1,
- (i, j + 1), or
- (i + 1, j + 1) — only if i < 3.
However, there are n obstacles blocking your path. k-th obstacle is denoted by three integers ak, lk and rk, and it forbids entering any cell (ak, j) such that lk ≤ j ≤ rk.
You have to calculate the number of different paths from (2, 1) to (2, m), and print it modulo 109 + 7.
The first line contains two integers n and m (1 ≤ n ≤ 104, 3 ≤ m ≤ 1018) — the number of obstacles and the number of columns in the matrix, respectively.
Then n lines follow, each containing three integers ak, lk and rk (1 ≤ ak ≤ 3, 2 ≤ lk ≤ rk ≤ m - 1) denoting an obstacle blocking every cell (ak, j) such that lk ≤ j ≤ rk. Some cells may be blocked by multiple obstacles.
Print the number of different paths from (2, 1) to (2, m), taken modulo 109 + 7. If it is impossible to get from (2, 1) to (2, m), then the number of paths is 0.
2 5 1 3 4 2 2 3
2
DP+矩阵快速幂。
把一个列的每格的方法数定义为一个1*3的列向量,每一列都可以由前一列DP,那么可以把整个地图分成很多段,每段用一个递推矩阵DP。有多少列,就左乘多少次这个矩阵。
多个障碍的话,根据障碍出现和消失的位置排序,依次处理。
要注意的是,障碍可以重叠。
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=10005,inf=0x3f3f3f3f,size=3;
const ll llinf=0x3f3f3f3f3f3f3f3f,mod=1e9+7;
const ld pi=acos(-1.0L);
ll ac[3];
struct block{
ll a,p;
bool f;
};
block b[maxn*2];
bool cmp(block a,block b) {
return a.p<b.p || (a.p==b.p&&a.f<b.f);
}
struct Matrix {
ll a[size][size];
};
Matrix ans,p,base;
Matrix operator*(const Matrix &x,const Matrix &y) {
int i,j,k;
Matrix ans;
for (i=0;i<size;i++) {
for (j=0;j<size;j++) {
ans.a[i][j]=0;
for (k=0;k<size;k++) {
ans.a[i][j]+=x.a[i][k]*y.a[k][j];
ans.a[i][j]%=mod;
}
}
}
return ans;
}
Matrix fastpower(Matrix base,ll index) {
Matrix ans,now;
int i,j;
for (i=0;i<size;i++) {
for (j=0;j<size;j++) {
if (i==j) ans.a[i][j]=1; else ans.a[i][j]=0;
}
}
now=base;
ll k=index;
while (k) {
if (k%2) ans=ans*now;
now=now*now;
k/=2;
}
return ans;
}
void minu(ll i) {
for (int j=0;j<size;j++)
p.a[b[i].a][j]=0;
}
void add(ll i) {
for (int j=0;j<size;j++)
p.a[b[i].a][j]=base.a[b[i].a][j];
}
int main() {
ll n,m,i,j,x,y,z;
scanf("%I64d%I64d",&n,&m);
for (i=1;i<=n;i++) {
scanf("%I64d%I64d%I64d",&x,&y,&z);
b[i*2-1].a=x-1;b[i*2-1].p=y;b[i*2-1].f=1;
b[i*2].a=x-1;b[i*2].p=z+1;b[i*2].f=0;
}
ac[0]=ac[1]=ac[2]=0;
sort(b+1,b+n*2+1,cmp);
for (i=0;i<size;i++)
for (j=0;j<size;j++) {
if (i==2&&j==0) p.a[i][j]=0; else
if (i==0&&j==2) p.a[i][j]=0; else p.a[i][j]=1;
base.a[i][j]=p.a[i][j];
}
for (i=0;i<size;i++)
for (j=0;j<size;j++)
if (i!=j) ans.a[i][j]=0; else ans.a[i][j]=1;
ans=fastpower(p,b[1].p-2)*ans;
i=0;
while (i<n*2) {
i++;
if (b[i].f==0) ac[b[i].a]--; else ac[b[i].a]++;
if (ac[b[i].a]==0) add(i);
if (ac[b[i].a]==1&&b[i].f==1) minu(i);
while (b[i+1].p==b[i].p&&i<n*2) {
i++;
if (b[i].f==0) ac[b[i].a]--; else ac[b[i].a]++;
if (ac[b[i].a]==0) add(i);
if (ac[b[i].a]==1&&b[i].f==1) minu(i);
}
if (i==n*2) break;
ans=fastpower(p,b[i+1].p-b[i].p)*ans;
}
ans=fastpower(p,m-b[n*2].p+1)*ans;
ll sum=ans.a[1][1];
printf("%I64d\n",sum);
return 0;
}
二分答案。
从左到右扫描,找到一个人数不符要求的地方,就补上少的人数。
很自然的,这时把这些少的人尽量放在右边最优,覆盖的范围最广。
利用前缀和完成上述check操作。
最后看一下补的人有没有k个就好了。
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=500005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
ll sum[maxn],a[maxn],t[maxn];
bool check(ll mid,ll q,ll p,ll n) {
ll i,j,k=p,ssum=0;
mem0(t);
for (i=1;i<=n;i++) {
ssum+=sum[i]+t[i];
if (ssum>=mid) continue;
ll com=mid-ssum;
k-=com;
if (k<0) return false;
ssum+=com;
t[min(n+1,i+q*2+1)]-=com;
}
return true;
}
int main() {
ll n,k,r,i,j,l,mid,q;
scanf("%I64d%I64d%I64d",&n,&q,&k);
mem0(sum);
for (i=1;i<=n;i++) {
scanf("%I64d",&a[i]);
sum[max(1ll,i-q)]+=a[i];
sum[min(n+1,i+q+1)]-=a[i];
}
l=1;r=2e18;ll ans=0;
while (l<=r) {
mid=(l+r)/2;
if (check(mid,q,k,n)) ans=mid,l=mid+1; else r=mid-1;
}
printf("%I64d\n",ans);
return 0;
}