codeforces.R174题解全

http://codeforces.com/contest/283/

     虽然比赛中还是犯了两个很2的错误,但是还是顺利升回红色id了=。=~。。D题推导中连续整数和竟然写少了个2~,e题读错题了。。悲剧啊

A.比较简单,操作时候一直维护总和就可以了。。对于操作1(前a个数全部增加x)以及操作2(添加一个新数字在队列最后)显然可以顺利做到,而操作3则要求求出当前队列最后数字的值,我们可以用lasy的思想处理操作1即可以,如在head ~head+a 的位置增加x,我们可以在head+a的位置记录这个x(mark[head+ai]+=x),当head+a被删除之后后,才会要求求出head+ai-1位置的值,所以在删除head+a后我们将记录在该位置上的x值传到上一位即可(mark[head+a-1] += mark[head+a])..时间空间复杂度均O(n)

B.记忆化搜索,对于每个x值,其下面两种可能操作,x+=a[x] , x-=a[x]。。故总共只有O(n*2)种状态,这里用dp[i][0]表示x=i,下一次操作x变化为i-a[i],  dp[i][1]表示x=i,下一次操作x变化为i+a[i]...预处理dp[2~n][0],即可以回答所有询问,ps:当i-a[i] == 1时,此时将陷入死循环dp[i][0]=-1.时间空间复杂度均为O(n).

C.预处理+dp..由于题目中对于硬币数量约束条件有该限制:It is known that all bi are distinct and all ci are distinct.。。故可以硬币数量约束条件必将构成链或者环关系。。显然环意味着无解,对于链关系Ai1 < Ai2 < Ai3 < Ai4 < Ai5...< Ain(Ai表示硬币数量 ,Bi表示硬币价值),则其总价值可以表示成如下关系:

            Ai1Bi1+Ai2Bi3+..+AinBin= Ai1(Bi1+Bi2+Bi3+..Bin) + (Ai2-Ai1)Bi2+...+(Ain-Ai1)Bin

                                                  =Ai1(Bi1+Bi2+...+Bin) + (Ai2-Ai1)(Bi2+..+Bin)+(Ai3-Ai2)(Bi3+...+Bin) +..+(Ain-Ain-1)Bin

此时我们可以设 a'i = (Ai-Ai-1)  b'i = (Bi+..+Bin);并令总价值tol = tol - (b'i2+..b'in) 此时问题于原问题等价,但是没有了任何硬币数量约数。。所以预处理完当成普通无限多重背包处理即可。

D.dp...

       首先要求分析何种情况下x能表示成y个连续整数的和,显然y个连续整数和可以表示成(2k+y+1)*y/2..分情况讨论,当y为奇数时,显然(2k+y+1)/2可以等于任意整数,故此时的充要条件为y是x的因子即x%y==0; 当y为偶数时,(2k+y+1)为任意奇数,y/2必须是x的因子,且x/(y/2)为奇数,故如果我们用2^k*A(A%2==1)来表示x,则可以此时y=2^(k+1)*B,B为A的因子。。

      综上,有结论当x=2kA(A%2==0)y取值集合为{A的因子}υ {A的因子}*2k+1

      之后的dp过程则异常简单,dp[i]表示当第i个数不改变时候,使得前i个数满足题目的序列要求的最小代价。。转移则枚举j<i,假设j是i之前上一个不改变的位置,判断改变j+1~i-1位置上的数字均改变后能否使得构成满足题目要求序列,显然j+1~i-1的改变是可以贪心进行的,w[j] = 2ba..有上结论可以知因子a显然保留下来更优,故w[j+1] = a或者2b+1a。。如果w[j] = 2b[j]a[j] ,w[i] = 2b[i]a[i],满足a[j]%a[i]==0 && (b[j]+i-j == b[i] || b[i]<=i-j-1),时我们必然有方法构造j+1~i-1使得序列满足要求。。

E.线段树。。

       首先考虑一个子问题如何统计题目要求的三元组个数,此处有一非常经典解法求不满足要求的三元组个数,设三元组(a1,a2,a3)不满足要求,则必然且只有一个ai大于其他两个。。设wi表示比i强的奶牛数目,则答案为 n*(n-1)*(n-2)/6 - Σwi(wi-1)/2 ...

       之后考虑如何求wi数目,如果没有题目中出现的翻转操作,结果将如下,00000011111111 i左边的奶牛均为0表示其若于i,i右边奶牛均为1表示则其强于1.。之后考虑翻转区间ak,bk ,如i<ak该操作不会对wi结果造成任何影响,直到i>=ak此时我们可以将ak~bk的位置的01值翻转(基本的线段树操作),直到i>bk,此时该区间再次不会对wi结果产生影响,我们再执行一遍ak~bk位置01值翻转即可。。至此我们得到了一个求wi的方法,从左往右求wi,每次把新产生效果翻转区间ak~bk取反 同时把新失去效果的翻转区间的ak~bk取反。。统计1总数。。。

代码:

View Code
 1 //By Lin
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<set>
 7 #include<vector>
 8 #include<map>
 9 #include<queue>
10 #include<cctype>
11 #include<cmath>
12 
13 #define eps 1e-9
14 #define N 201010
15 #define sqr(x) ((x)*(x))
16 #define Rep(i,n) for(int i = 0; i<n; i++)
17 #define foreach(i,n) for( __typeof(n.begin()) i = n.begin(); i!=n.end(); i++)
18 #define X first
19 #define Y second
20 #define mp(x,y) make_pair(x,y)
21 
22 using namespace std;
23 typedef long long LL;
24 typedef pair<int,int> pii;
25 
26 int        que[N],mark[N];
27 int        main(){
28     int    n = 0, cas,kind , a , x;
29     double    sum = 0;
30     scanf("%d", &cas );
31     int g = 0 , h = 0;
32     que[h++] = 0;
33     while ( cas -- ){
34         scanf("%d", &kind );
35         if ( kind == 1 ) {
36             scanf("%d%d",&a, &x );
37             sum += x*1.0*a;
38             mark[g+a-1] += x;
39         }
40         else if ( kind == 2 ){
41             scanf("%d", &x );
42             mark[h] = 0;
43             que[h++] = x;
44             sum += x;
45         }
46         else {
47             mark[h-2] += mark[h-1];
48             sum -= que[h-1]+mark[h-1];
49             h--;
50         }
51         printf("%.10f\n", sum/(h-g) );
52     }
53 
54     return 0;
55 }
View Code
 1 //By Lin
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<set>
 7 #include<vector>
 8 #include<map>
 9 #include<queue>
10 #include<cctype>
11 #include<cmath>
12 
13 #define eps 1e-9
14 #define N 200010
15 #define sqr(x) ((x)*(x))
16 #define Rep(i,n) for(int i = 0; i<n; i++)
17 #define foreach(i,n) for( __typeof(n.begin()) i = n.begin(); i!=n.end(); i++)
18 #define X first
19 #define Y second
20 #define mp(x,y) make_pair(x,y)
21 
22 using namespace std;
23 typedef long long LL;
24 typedef pair<int,int> pii;
25 
26 int        mark[N][2],a[N],n;
27 LL        dp[N][2];
28 bool    g[N][2];
29 
30 void    solve(int i,int k){
31     mark[i][k] = 1;
32     dp[i][k] = a[i];
33     int j = i;
34     if ( k ) j+=a[i]; else j-=a[i];
35     
36     if ( j >=1 && j <= n ){
37         if ( j == 1 && (k^1) == 0 ) g[i][k] = 1;
38         else if ( mark[j][k^1] == 1 ) dp[i][k] = -1;
39         else {
40             if ( mark[j][k^1] == 0 ) solve(j,k^1);
41             if ( dp[j][k^1] == -1 ) dp[i][k] = -1;
42             else {
43                 dp[i][k] += dp[j][k^1];
44                 g[i][k] = g[j][k^1];
45             }
46         }
47     }
48     else g[i][k] = 0;
49 
50     mark[i][k] = 2;
51 }
52 
53 int        main(){
54     scanf("%d", &n );
55     for(int i = 2; i<=n; i++) scanf("%d", &a[i] );
56     mark[1][1] = 1;
57     for(int i = 2; i<=n; i++)
58         if ( mark[i][0]==0 ) {
59             solve(i,0);
60         }
61     for(int i = 1; i<=n-1; i++) {
62         if ( dp[i+1][0] == -1 ) printf("-1\n");
63         else printf("%I64d\n" , dp[i+1][0]+i+(g[i+1][0]?i:0) );
64     }
65     return 0;
66 }
View Code
 1 //By Lin
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<set>
 7 #include<vector>
 8 #include<map>
 9 #include<queue>
10 #include<cctype>
11 #include<cmath>
12 
13 #define eps 1e-9
14 #define sqr(x) ((x)*(x))
15 #define Rep(i,n) for(int i = 0; i<n; i++)
16 #define foreach(i,n) for( __typeof(n.begin()) i = n.begin(); i!=n.end(); i++)
17 #define X first
18 #define Y second
19 #define mp(x,y) make_pair(x,y)
20 
21 using namespace std;
22 typedef long long LL;
23 typedef pair<int,int> pii;
24 
25 #define N 305
26 #define M 100010
27 #define MOD 1000000007 
28 int        n,q,tol;    
29 int        to[N];
30 int        mark[N],a[N];
31 int        dp[2][M];
32 bool    st[N];
33 
34 bool    dfs(int x){
35     mark[x] = 2;
36     if ( to[x] == 0 ) return true;
37     if ( mark[to[x]] == 2 ) return false;
38     else if ( !dfs(to[x]) ) return false;
39     a[x] += a[to[x]];
40     return true;
41 }
42 
43 int        solve(){
44     for(int i = 1; i<=n; i++) 
45         if ( mark[i]==0 ) {
46             st[i] = true;
47             if ( !dfs(i) ) return 0;
48         }
49     for(int i = 1; i<=n; i++){
50         if ( mark[i] == 1 ) return 0;
51         if ( !st[i] ) tol -= a[i];
52         if ( tol < 0 ) return 0;
53     }
54     memset( dp , 0 , sizeof(dp) );
55     dp[0][0] = 1;
56     for(int i = 0; i<n; i++){
57         int g = i%2 , h = (i+1)%2;
58         memset( dp[h] , 0 , sizeof(dp[h]) );
59         for(int j = 0; j<=tol; j++){
60             dp[h][j] += dp[g][j];
61             dp[h][j] %= MOD;
62             if ( j+a[i+1] <= tol ){
63                 dp[h][j+a[i+1]] += dp[h][j];
64                 dp[h][j+a[i+1]] %= MOD;
65             }
66         }
67     }
68     return dp[n%2][tol];
69 }
70 int        main(){
71     scanf("%d%d%d", &n, &q, &tol );
72     Rep(i,n) scanf("%d", &a[i+1] );
73     while ( q -- ) {
74         int x,y;
75         scanf("%d%d", &x, &y );
76         to[y] = x;
77         mark[x] = 1;
78     }
79     printf("%d\n" , solve() );
80     return 0;
81 }
View Code
 1 //By Lin
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<set>
 7 #include<vector>
 8 #include<map>
 9 #include<queue>
10 #include<cctype>
11 #include<cmath>
12 
13 #define eps 1e-9
14 #define N 10010
15 #define sqr(x) ((x)*(x))
16 #define Rep(i,n) for(int i = 0; i<n; i++)
17 #define foreach(i,n) for( __typeof(n.begin()) i = n.begin(); i!=n.end(); i++)
18 #define X first
19 #define Y second
20 #define mp(x,y) make_pair(x,y)
21 
22 using namespace std;
23 typedef long long LL;
24 typedef pair<int,int> pii;
25 
26 int        n;
27 LL        a[N];
28 int        dp[N],b[N];
29 int        main(){
30     scanf("%d", &n );
31     Rep(i,n) {
32         cin>>a[i];
33         while ( a[i]%2 == 0 ){
34             b[i]++;
35             a[i]/=2;
36         }
37     }
38     dp[0] = 1;
39     int    ans = n;
40     Rep(i,n){
41         dp[i] = i;
42         Rep(j,i) 
43             if ( a[j]%a[i] == 0 && (b[j]+i-j>=b[i] || b[i]<=i-j-1) )
44                 dp[i] = min( dp[j]+i-j-1 , dp[i] );
45         ans = min( ans , n-i-1+dp[i] );
46     }
47     printf("%d\n" , ans );
48     return 0;
49 }
View Code
  1 //By Lin
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<set>
  7 #include<vector>
  8 #include<map>
  9 #include<queue>
 10 #include<cctype>
 11 #include<cmath>
 12 
 13 #define eps 1e-9
 14 #define N 100010
 15 #define sqr(x) ((x)*(x))
 16 #define Rep(i,n) for(int i = 0; i<n; i++)
 17 #define foreach(i,n) for( __typeof(n.begin()) i = n.begin(); i!=n.end(); i++)
 18 #define X first
 19 #define Y second
 20 #define mp(x,y) make_pair(x,y)
 21 
 22 using namespace std;
 23 typedef long long LL;
 24 typedef pair<int,int> pii;
 25 
 26 int        n,m,data[N];
 27 pii        que[N*2];
 28 
 29 struct    Segtree{
 30     int    left[N*4],right[N*4];
 31     int    key[N*4][2],mark[N*4];
 32     void    down(int step){
 33         if ( !mark[step] ) return;
 34         mark[step] = 0;
 35         Rep(k,2)
 36             mark[step*2+k]^= 1,
 37             swap( key[step*2+k][0] , key[step*2+k][1] );
 38     }
 39     void    build(int l,int r,int step){
 40         left[step] = l , right[step] = r;
 41         key[step][0] = 0 , key[step][1] = r-l+1;
 42         mark[step] = 0; 
 43         if ( l == r ) return;
 44         int    mid=(l+r)/2;
 45         build(l,mid,step*2);
 46         build(mid+1,r,step*2+1);
 47     }
 48     void    updata(int l,int r,int step){
 49         if ( left[step] == l && right[step] == r ){
 50             mark[step] ^= 1;
 51             swap( key[step][0] , key[step][1] );
 52             return;
 53         }
 54         down(step);
 55         int    mid=(left[step]+right[step])/2;
 56         if ( r<=mid ) updata(l,r,step*2);
 57         else if ( mid<l ) updata(l,r,step*2+1);
 58         else{
 59             updata(l,mid,step*2);
 60             updata(mid+1,r,step*2+1);
 61         }
 62         Rep(k,2) key[step][k] = key[step*2][k]+key[step*2+1][k];
 63     }
 64     int        ask(int l,int r,int k,int step){
 65         if ( left[step] == l && right[step] == r ) return key[step][k];
 66         down(step);
 67         int    mid=(left[step]+right[step])/2;
 68         if ( r <= mid ) return ask(l,r,k,step*2);
 69         else if ( mid < l ) return ask(l,r,k,step*2+1);
 70         else return ask(l,mid,k,step*2)+ask(mid+1,r,k,step*2+1);
 71     }
 72 }tree;
 73 
 74 int        main(){
 75     scanf("%d%d", &n, &m );
 76     Rep(i,n) scanf("%d", &data[i] );
 77     sort( data , data+n );
 78     Rep(i,m) {
 79         int x,y;
 80         scanf("%d%d", &x, &y );
 81         que[i*2] = mp(x,y);
 82         que[i*2+1] = mp(y+1,-x);
 83     }
 84     sort( que , que+m*2 );
 85     tree.build(0,n,1);
 86     int    j = 0;
 87     LL    ans = 0;
 88     Rep(i,n){
 89         while ( j<2*m && data[i] >= que[j].X ){
 90             int    l,r;
 91             if ( que[j].Y > 0 ) l = i , r = upper_bound(data,data+n,que[j].Y)-data-1;
 92             else r = i-1 , l = lower_bound(data,data+n,-que[j].Y)-data;
 93             if ( l<=r ) tree.updata(l,r,1);
 94             j++;
 95         }
 96         int tol = (i?tree.ask(0,i-1,0,1):0)+(i<n-1?tree.ask(i+1,n-1,0,1):0);
 97         ans += ((LL)tol)*(tol-1)/2;
 98         tree.updata(i,i,1);
 99     }
100     ans = ((LL)n)*(n-1)*(n-2)/6-ans;
101     cout<<ans<<endl;
102     return 0;
103 }

 

posted @ 2013-03-19 18:25 lzqxh 阅读(...) 评论(...) 编辑 收藏