【codeforces #278(div 1)】ABCD题解

来源:互联网 发布:淘宝分销代销的区别 编辑:程序博客网 时间:2024/05/17 08:09
A. Fight the Monster
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

A monster is attacking the Cyberland!

Master Yang, a braver, is going to beat the monster. Yang and the monster each have 3 attributes: hitpoints (HP), offensive power (ATK) and defensive power (DEF).

During the battle, every second the monster's HP decrease by max(0, ATKY - DEFM), while Yang's HP decreases bymax(0, ATKM - DEFY), where index Y denotes Master Yang and index M denotes monster. Both decreases happen simultaneously Once monster's HP ≤ 0 and the same time Master Yang's HP > 0, Master Yang wins.

Master Yang can buy attributes from the magic shop of Cyberland: h bitcoins per HPa bitcoins per ATK, and d bitcoins per DEF.

Now Master Yang wants to know the minimum number of bitcoins he can spend in order to win.

Input

The first line contains three integers HPY, ATKY, DEFY, separated by a space, denoting the initial HPATK and DEF of Master Yang.

The second line contains three integers HPM, ATKM, DEFM, separated by a space, denoting the HPATK and DEF of the monster.

The third line contains three integers h, a, d, separated by a space, denoting the price of HPATK and DEF.

All numbers in input are integer and lie between 1 and 100 inclusively.

Output

The only output line should contain an integer, denoting the minimum bitcoins Master Yang should spend in order to win.

Sample test(s)
input
1 2 11 100 11 100 100
output
99
input
100 100 1001 1 11 1 1
output
0
Note

For the first sample, prices for ATK and DEF are extremely high. Master Yang can buy 99 HP, then he can beat the monster with 1HP left.

For the second sample, Master Yang is strong enough to beat the monster, so he doesn't need to buy anything.

暴力。

h2:每秒减少max(0,a1-d2)

h1:每秒减少max(0,a2-d1)

要求让h1比h2先减完。


先考虑一种特殊情况:

如果两人都是每秒减少0,那么此时增加a1,d1都是起反作用的,只能增加h1。


其他情况下,d1最多增加到a2(再大没有意义),a1最多增加到d2+h1(再大没有意义)。


那么我们枚举d1,a1的增加量(O(n^2)  n=100),可以O(1)算出来要获胜h1增加多少(代码中这里也是枚举的。。),最后输出最小费用即可。

#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <cmath>#include <cstdlib>using namespace std;int h1,h2,a1,a2,d1,d2,hc,dc,ac;int win(int h1,int h2,int a1,int d1,int a2,int d2){int x1=max(0,a2-d1),x2=max(0,a1-d2);if (x1==0&&x2!=0) return 1;if (x2==0) return 0;int k1=ceil((double)h1/x1),k2=ceil((double)h2/x2);if (k1>k2) return 1;return 0;}int main(){        cin>>h1>>a1>>d1;cin>>h2>>a2>>d2;cin>>hc>>ac>>dc;int ans=1000000;if (win(h1,h2,a1,d1,a2,d2)){cout<<0<<endl;return 0;}int k;if (max(a2-d1,0)==0){cout<<(d2+1-a1)*ac<<endl;return 0;}k=ceil((double)h1/(a2-d1));for (int d=0;d<=a2;d++)for (int a=0;a<=200;a++){if (win(h1,h2,a1+a,d1+d,a2,d2)){ans=min(ans,a*ac+d*dc);continue;}for (int i=k+1;i<=100;i++){int h=(i-1)*(a2-d1)+1-h1;if (win(h1+h,h2,a1+a,d1+d,a2,d2)){ans=min(ans,h*hc+a*ac+d*dc);continue;}}}cout<<ans<<endl;return 0;}


B. Strip
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Alexandra has a paper strip with n numbers on it. Let's call them ai from left to right.

Now Alexandra wants to split it into some pieces (possibly 1). For each piece of strip, it must satisfy:

  • Each piece should contain at least l numbers.
  • The difference between the maximal and the minimal number on the piece should be at most s.

Please help Alexandra to find the minimal number of pieces meeting the condition above.

Input

The first line contains three space-separated integers n, s, l (1 ≤ n ≤ 105, 0 ≤ s ≤ 109, 1 ≤ l ≤ 105).

The second line contains n integers ai separated by spaces ( - 109 ≤ ai ≤ 109).

Output

Output the minimal number of strip pieces.

If there are no ways to split the strip, output -1.

Sample test(s)
input
7 2 21 3 1 2 4 1 2
output
3
input
7 2 21 100 1 100 1 100 1
output
-1
Note

For the first sample, we can split the strip into 3 pieces: [1, 3, 1], [2, 4], [1, 2].

For the second sample, we can't let 1 and 100 be on the same piece, so no solution exists.


题解中的做法是单调队列:

使用一个单增队列和一个单减队列求出g[i],表示i可以由g[i]到i-l转移;

再用一个单增队列,求出f[i]表示前i个数最少分成f[i]段,f[i]=min(f[k]+1)  (g[i]<=k<=i-l)


其实也可以用set来做(虽然慢一点,但是好写多了):

两个set:

s放a[i],dp放f[i]


每次插入a[i],如果s中max-min>S,那么就把最靠前a[j]的弹出,把他对应的f[j-1]也弹出(如果被放入的话);


如果i-j+1>=l就把f[i-j]插入。


f[i]就是dp这个set中最小的元素+1


#include <iostream>#include <cstring>#include <cmath>#include <cstdio>#include <algorithm>#include <set>#define mp make_pair#define pa pair<int,int>#define M 100000+5#define inf 0x3f3f3f3fusing namespace std;int f[M],n,ss,l,a[M];multiset<int> s,dp;int main(){        scanf("%d%d%d",&n,&ss,&l);for (int i=1;i<=n;i++)scanf("%d",&a[i]);for (int i=1,j=1;i<=n;i++){s.insert(a[i]);for (;*s.rbegin()-*s.begin()>ss;j++){s.erase(s.find(a[j]));if (i-j>=l)dp.erase(dp.find(f[j-1]));}        if (i-j+1>=l) dp.insert(f[i-l]);if (dp.begin()==dp.end())f[i]=inf;else f[i]=*dp.begin()+1;}if (f[n]>=inf)puts("-1");else cout<<f[n]<<endl;return 0;}


C. Prefix Product Sequence
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Consider a sequence [a1, a2, ... , an]. Define its prefix product sequence .

Now given n, find a permutation of [1, 2, ..., n], such that its prefix product sequence is a permutation of [0, 1, ..., n - 1].

Input

The only input line contains an integer n (1 ≤ n ≤ 105).

Output

In the first output line, print "YES" if such sequence exists, or print "NO" if no such sequence exists.

If any solution exists, you should output n more lines. i-th line contains only an integer ai. The elements of the sequence should be different positive integers no larger than n.

If there are multiple solutions, you are allowed to print any of them.

Sample test(s)
input
7
output
YES1436527
input
6
output
NO
Note

For the second sample, there are no valid sequences.


首先1肯定放第一个,n肯定放最后一个:

1放中间就和他前面的模值相同了;n放中间后面mod n全是0。


然后可以发现除了1,4和质数之外,答案都是NO,因为合数(n-1)! mod n=n,也就是说至少有两个mod n=0。


那么质数如何求方案数?


用这样的式子:

i=2

i/(i-1) * (i+1)/i * (i+2)/(i+1)...*(i+k)/(i+k-1)=i+k

第i位是i/(i-1),就可以得到一个排列了。


可以证明每一位的i/(i-1)都是不同的。

#include <iostream>#include <cstring>#include <cmath>#include <cstdio>#include <algorithm>using namespace std;int n;int ni(int x,int n,int mod){long long b=x,ans=1;while (n){if (n&1) ans=ans*b%mod;b=b*b%mod;n>>=1;}return (int)(ans%mod);}int main(){cin>>n;if (n==1){printf("YES\n1\n");return 0;}if (n==4){printf("YES\n1\n3\n2\n4\n");return 0;}for (int i=2;i<n;i++)if (n%i==0){puts("NO");return 0;}printf("YES\n1\n");for (int i=2;i<n;i++)printf("%d\n",(int)(1LL*i*ni(i-1,n-2,n)%n));printf("%d\n",n);return 0;}


D. Conveyor Belts
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Automatic Bakery of Cyberland (ABC) recently bought an n × m rectangle table. To serve the diners, ABC placed seats around the table. The size of each seat is equal to a unit square, so there are 2(n + m) seats in total.

ABC placed conveyor belts on each unit square on the table. There are three types of conveyor belts: "^", "<" and ">". A "^" belt can bring things upwards. "<" can bring leftwards and ">" can bring rightwards.

Let's number the rows with 1 to n from top to bottom, the columns with 1 to m from left to right. We consider the seats above and below the top of the table are rows 0 and n + 1 respectively. Also we define seats to the left of the table and to the right of the table to be column 0 and m + 1. Due to the conveyor belts direction restriction there are currently no way for a diner sitting in the row n + 1 to be served.

Given the initial table, there will be q events in order. There are two types of events:

  • "A x y" means, a piece of bread will appear at row x and column y (we will denote such position as (x, y)). The bread will follow the conveyor belt, until arriving at a seat of a diner. It is possible that the bread gets stuck in an infinite loop. Your task is to simulate the process, and output the final position of the bread, or determine that there will be an infinite loop.
  • "C x y c" means that the type of the conveyor belt at (x, y) is changed to c.

Queries are performed separately meaning that even if the bread got stuck in an infinite loop, it won't affect further queries.

Input

The first line of input contains three integers nm and q (1 ≤ n ≤ 105, 1 ≤ m ≤ 10, 1 ≤ q ≤ 105), separated by a space.

Next n lines, each line contains m characters, describing the table. The characters can only be one of "<^>".

Next q lines, each line describes an event. The format is "C x y c" or "A x y" (Consecutive elements are separated by a space). It's guaranteed that 1 ≤ x ≤ n, 1 ≤ y ≤ mc is a character from the set "<^>".

There are at most 10000 queries of "C" type.

Output

For each event of type "A", output two integers txty in a line, separated by a space, denoting the destination of (x, y) is (tx, ty).

If there is an infinite loop, you should output tx = ty =  - 1.

Sample test(s)
input
2 2 3>>^^A 2 1C 1 2 <A 2 1
output
1 3-1 -1
input
4 5 7><<^<^<^^>>>>^>>^>>^A 3 1A 2 2C 1 4 <A 3 1C 1 2 ^A 3 1A 2 2
output
0 4-1 -1-1 -10 20 2
Note

For the first sample:

If the bread goes from (2, 1), it will go out of the table at (1, 3).

After changing the conveyor belt of (1, 2) to "<", when the bread goes from (2, 1) again, it will get stuck at "><", so output is ( - 1,  - 1).

分块/线段树。


分块很好写:

m很小,所以按照n分为sqrt(n)块,维护在每一块中能走到哪里,修改也只修改所在块。

注意修改的时候对于这一块的最上层要特判一下,因为上面那层也许还没更新。


因此每一个询问复杂度O(n/sqrt(n))=O(sqrt(n));


每一个修改复杂度O(m*sqrt(n))


线段树是按照n分段的,每个节点x维护tree[x][i]:表示从(r,i)能走到(l,tree[x][i]),l和r分别是左右子树,然后修改就是区间合并区间查询的问题了。


#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <cstdlib>#include <cmath>#define mp make_pair#define M 100000+5using namespace std;pair<int,int> f[M][20];char s[M][20];int z,n,m,q,num[M],cnt;void Modify(int x1,int x2){for (int i=x1;i<=x2;i++){for (int j=0;j<=m+1;j++)f[i][j]=mp(i,j);for (int j=1;j<=m;j++)if (s[i][j]=='^')f[i][j]=i==x1?mp(x1-1,j):f[i-1][j];for (int j=1;j<=m;j++)if (s[i][j]=='<')f[i][j]=f[i][j-1];for (int j=m;j;j--)if (s[i][j]=='>')f[i][j]=f[i][j+1];}}int main(){        scanf("%d%d%d",&n,&m,&q);for (int i=1;i<=m;i++)f[0][i]=mp(0,i);for (int i=1;i<=n;i++)scanf("%s",s[i]+1);z=sqrt(n)+1;cnt=-1;for (int i=1;i<=n;i+=z){cnt++;Modify(i,min(n,i+z-1));for (int j=i;j<=min(n,i+z-1);j++)num[j]=cnt;}while (q--){char t[5];int x,y;scanf("%s%d%d",t,&x,&y);if (t[0]=='A'){int xx=x,yy=y;int ok=1;while (xx>=1&&yy>=1&&yy<=m){    int nx=f[xx][yy].first,ny=f[xx][yy].second;                    if (nx==xx&&ny>=1&&ny<=m)    {ok=0;puts("-1 -1");break;    }    xx=nx,yy=ny;}if (ok)printf("%d %d\n",xx,yy);}else{scanf("%s",t);int fi=num[x]*z+1;s[x][y]=t[0];Modify(x,min(fi+z-1,n));}}return 0; }


感悟:

看来我线段树还是没学好,D有时间写一下。。

1 0
原创粉丝点击