hdu 4059 The Boss on Mars 容斥原理 数列通项公式

The Boss on Mars

为了高效求出数列的项 $ a_i=\sum\limits^n_{i=1} i^4 $,不使用通项公式是无法实现的。
另外实际分解所得的质因数的种类并不多,无需浪费大量时间、空间筛选大质数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/** Aug 27, 2015 2:45:37 PM
* PrjName:hdu4059
* @author Semprathlon
*/
import java.io.*;
import java.util.*;
public class Main {
static PrintWriter out=new PrintWriter(System.out);
static int maxn=105;
static Vector<Integer> vec=new Vector<Integer>();
static Vector<Integer> get_prime_factor(int n){
Vector<Integer> res=new Vector<Integer>();
for(int i=2;i*i<=n;i++)
if (n%i==0){
res.add(i);
while(n%i==0)
n/=i;
}
if (n>1) res.add(n);
return res;
}
final static long mod=1000000007L;
static long pow(long n,long m,long mod){
long res=1L;
while(m>0L){
if ((m&1L)>0L) res=res*n%mod;
n=n*n%mod;
m>>=1;
}
return res;
}
static long div(long a,long b,long mod){
return a*pow(b,mod-2,mod)%mod;
}
static long sum(int n,long mod){
long res=n;
res*=2*n+1;res%=mod;
res*=n+1;res%=mod;
res*=(3L*n*n+3*n-1)%mod;res%=mod;
return div(res,30,mod);
}
static long solve(Vector<Integer> vec,int n){
long res=0L;
int m=vec.size();
for(int i=1;i<(1L<<m);i++){
boolean tag=false;
int tmp=1;
for(int j=0;j<m;j++)
if (((1L<<j)&i)>0){
tmp*=vec.get(j);
tmp%=mod;
tag^=true;
}
res=res+(tag?1:-1)*(pow(tmp,4,mod)*sum(n/tmp,mod)%mod);
res%=mod;
}
return res;
}
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
InputReader in=new InputReader(System.in);
int T=in.nextInt();
while(T-->0){
int n=in.nextInt();
Vector<Integer> v=get_prime_factor(n);
out.println((sum(n,mod)-solve(v,n)+mod)%mod);
}
out.flush();
out.close();
}

}

另有一个未知的通过矩阵快速幂计算该数列项的方法(求以下矩阵的n次方)。

1 1 4 6 4 1
0 1 4 6 4 1
0 0 1 3 3 1
0 0 0 1 2 1
0 0 0 0 1 1
0 0 0 0 0 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void init()  
{
int i,j;
//构造矩阵
ONE.mat[1][1]=1;ONE.mat[1][2]=1;ONE.mat[1][3]=4;
ONE.mat[1][4]=6;ONE.mat[1][5]=4;ONE.mat[1][6]=1;
ONE.mat[2][1]=0;ONE.mat[2][2]=1;ONE.mat[2][3]=4;
ONE.mat[2][4]=6;ONE.mat[2][5]=4;ONE.mat[2][6]=1;
ONE.mat[3][1]=0;ONE.mat[3][2]=0;ONE.mat[3][3]=1;
ONE.mat[3][4]=3;ONE.mat[3][5]=3;ONE.mat[3][6]=1;
ONE.mat[4][4]=1;ONE.mat[4][5]=2;ONE.mat[4][6]=1;
ONE.mat[5][4]=0;ONE.mat[5][5]=1;ONE.mat[5][6]=1;
ONE.mat[6][6]=1;
yu[0]=0;
yu[1]=1;
LL x;
for(i=2;i<maxn;i++)//预处理1~200W的sum[x]
{
x=i%MOD;
x=x*i;
x=x%MOD;
x=x*i;
x=x%MOD;
x=x*i;
x=x%MOD;
yu[i]=yu[i-1]+x;
yu[i]=yu[i]%MOD;
}
AA[1]=ONE;
for(i=2;i<30;i++)AA[i]=AA[i-1]*AA[i-1];
}

最后以这种方式取得计算结果(再乘上以下矩阵):

1 0 0 0 0 0
1 0 0 0 0 0
1 0 0 0 0 0
1 0 0 0 0 0
1 0 0 0 0 0
1 0 0 0 0 0
1
2
3
4
5
6
7
8
9
10
matrix A;  
LL kan(LL x)//求sum[x]
{
if(x<maxn)return yu[x];
matrix OP;
for(int i=1;i<=6;i++)OP.mat[i][1]=1;
A=powmul(ONE,x-1);
OP=A*OP;
return OP.mat[1][1];
}

hdu 4135 Co-prime 容斥原理

hdu 4135

具有教科书性质的容斥原理应用实例。
能不重复、不遗漏地选出所有合数,也就能得到质数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/** Aug 26, 2015 9:40:09 PM
* PrjName:hdu4135
* @author Semprathlon
*/
import java.io.*;
import java.util.*;
public class Main {
static int maxn=1001;
static int[] pri,fstp;
static Vector<Integer> vec=new Vector<Integer>();
static void get_prime(){
pri=new int[maxn];
fstp=new int[maxn];
for(int i=2;i<maxn;i++){
if (fstp[i]==0){
pri[++pri[0]]=i;
}
for(int j=1;j<=pri[0]&&i*pri[j]<maxn;j++){
int k=i*pri[j];
fstp[k]=pri[j];
if (i%pri[j]==0)
break;
}
}
}
static Vector<Integer> get_prime_factor(int n){
Vector<Integer> res=new Vector<Integer>();
res.clear();
for(int i=1;i<=pri[0]&&pri[i]*pri[i]<=n;i++)
if (n%pri[i]==0){
res.add(pri[i]);
while(n%pri[i]==0)
n/=pri[i];
}
if (n>1) res.add(n);
return res;
}
static long solve(long n,Vector<Integer> vec){
long res=0L;
final int m=vec.size();
for(long i=1L;i<(1L<<m);i++){
boolean tag=false;
long tmp=1L;
for(int j=0;j<m;j++)
if (((1L<<j)&i)>0){
tag^=true;
tmp*=vec.get(j).longValue();
}
res+=tag?n/tmp:-n/tmp;
}
return n-res;
}
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
get_prime();
InputReader in=new InputReader(System.in);
PrintWriter out=new PrintWriter(System.out);
int T=in.nextInt(),cas=0;
while(T-->0){
long a=in.nextLong();
long b=in.nextLong();
int n=in.nextInt();
vec=get_prime_factor(n);
out.println("Case #"+(++cas)+": "+(solve(b,vec)-solve(a-1,vec)));
}
out.flush();
out.close();
}
}

2013 ACM/ICPC Asia Regional Chengdu Online

1007 F(x)数位DP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/** Aug 22, 2015 5:23:42 PM
* PrjName:hdu4734
* @author Semprathlon
*/
import java.io.*;
import java.util.*;
public class Main {

/**
* @param args
*/
static int[][] f;
static int[] digit;
final static int maxm=4600;
static int fun(int n){
int res=0,tmp=1;
while(n>0){
res+=n%10*tmp;
tmp<<=1;
n/=10;
}
return res;
}
static void init(){
int tmp=1;
f=new int[10][maxm+1];
f[0][0]=1;
for(int i=1;i<10;i++){
for(int j=0;j<=maxm;j++)
for(int k=0;k<=9;k++)
if (j+tmp*k<=maxm)
f[i][j+tmp*k]+=f[i-1][j];
tmp<<=1;
}
for(int i=0;i<10;i++)
for(int j=1;j<=maxm;j++) f[i][j]+=f[i][j-1];
}
static int[] getdg(int n){
int[] res=new int[10];
while(n>0){
res[++res[0]]=n%10;
n/=10;
}
return res;
}
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
InputReader in=new InputReader(System.in);
PrintWriter out=new PrintWriter(System.out);
init();
int T=in.nextInt(),cas=0;
while(T-->0){
int A=in.nextInt();
int B=in.nextInt();
int m=fun(A);
digit=getdg(B);
int ans=0,tmp=1<<digit[0];
for(int i=digit[0];i>=1;i--){
tmp>>=1;
for(int k=0;k<digit[i];k++){

if (m-k*tmp>=0){
ans+=f[i-1][m-k*tmp];
}
}
m-=digit[i]*tmp;
if (m<0) break;

}
if (m>=0) ans++;
out.println("Case #"+(++cas)+": "+ans);
}
out.flush();
out.close();
}

}

磕磕绊绊的,到底有几大难?
期初是有过转化为背包问题的尝试,但是忽视了数位DP的处理手段;可先扩大枚举范围,再从中筛选。
预处理的两套循环不能杂糅在一起,因为先通过递推求了第i位、限制F(x)==j的解,然后才相加得到第i位、限制F(x)≤j的解。
筛选时注意“小于”的枚举方式。
最后还应留意B为可行解的条件。

1010 A Bit Fun

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/** Aug 22, 2015 4:28:18 PM
* PrjName:hdu4737
* @author Semprathlon
*/
import java.io.*;
import java.util.*;
public class Main {

/**
* @param args
*/
static int[] a;
static Queue<Integer> que=new LinkedList<Integer>();
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
InputReader in=new InputReader(System.in);
PrintWriter out=new PrintWriter(System.out);
int T=in.nextInt(),cas=0;
while(T-->0){
int n=in.nextInt();
int m=in.nextInt();
a=new int[n+1];
que.clear();
int ans=0;
for(int i=1;i<=n;i++){
a[i]=in.nextInt();
int k=que.size();
for(int j=0;j<k;j++){
int tmp=que.poll()|a[i];
if (tmp<m) que.add(tmp);
}
if (a[i]<m) que.add(a[i]);
ans+=que.size();
}
out.println("Case #"+(++cas)+": "+ans);
}
out.flush();
out.close();
}

}

并没有实现有些题解中所说的O(nlogn)或O(30n)的算法,但总的运行时间还是较短的?

BestCoder

1001 Victor and Machine

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)

  • Problem Description
    Victor has a machine. When the machine starts up, it will pop out a ball immediately. After that, the machine will pop out a ball every w seconds. However, the machine has some flaws, every time after x seconds of process the machine has to turn off for y seconds for maintenance work. At the second the machine will be shut down, it may pop out a ball. And while it’s off, the machine will pop out no ball before the machine restart.
    Now, at the 0 second, the machine opens for the first time. Victor wants to know when the n-th ball will be popped out. Could you tell him?

  • Input
    The input contains several test cases, at most 100 cases.
    Each line has four integers x, y, w and n. Their meanings are shown above。
    $ 1\leq x,y,w,n\leq 100 $ .

  • Output
    For each test case, you should output a line contains a number indicates the time when the n-th ball will be popped out.

  • Sample Input
    2 3 3 3
    98 76 54 32
    10 9 8 100

  • Sample Output
    10
    2664
    939

n-1的问题,自己刚开始出了点差错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/** Aug 22, 2015 7:03:37 PM
* PrjName:Bc52-01
* @author Semprathlon
*/
import java.io.*;
import java.util.*;
public class Main {

/**
* @param args
*/
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
StreamTokenizer in=new StreamTokenizer(new BufferedInputStream(System.in));
PrintWriter out=new PrintWriter(System.out);
while(in.nextToken()!=StreamTokenizer.TT_EOF){
int x=(int)in.nval;
in.nextToken();
int y=(int)in.nval;
in.nextToken();
int w=(int)in.nval;
in.nextToken();
int n=(int)in.nval;
if (n==1){
out.println(0);continue;
}
if (w>x){
out.println((n-1)*(x+y));continue;
}
else if (w==x){
out.println((n-1)/2*(x+y)+(n-1)%2*x);continue;
}
else{
int tmp=(x+w)/w;
out.println((n-1)/tmp*(x+y)+(n-1)%tmp*w);continue;
}
}
out.flush();
out.close();
}

}

Solving LCM【C0n,C1n, ,Cnn】

摘自《具体数学·计算机科学基础(英文版·第二版)》第5章习题及其解答:
0FF23C24-69C5-417E-BFA3-04CE6D477E87

BBACCBCF-BE37-40B5-8416-DD3FB5C6061A

$ \epsilon_p(n)$denotes the exponent of the prime p in the standard factorization of positive integer n.

$ \epsilon_p(n)$表示正整数n的因式分解中,质数p的指数。

BestCoder

1001 Distribution money

WA过一发,因为忽视了金额的分布范围。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* 2015年8月8日 下午7:02:20
* PrjName:Bc50-01
* @ Semprathlon
*/
import java.io.*;
import java.util.*;
public class Main {
static int[] a;
static int maxn=10001;
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
StreamTokenizer in=new StreamTokenizer(new BufferedInputStream(System.in));
PrintWriter out=new PrintWriter(System.out);
a=new int[maxn];
while(in.nextToken()!=StreamTokenizer.TT_EOF){
int n=(int)in.nval;
Arrays.fill(a, 0);
for(int i=1;i<=n;i++){
in.nextToken();
int k=(int)in.nval;
a[k]++;
}
int ans=-1;
for(int i=0;i<maxn;i++)
if ((a[i]<<1)>n)
ans=i;
//if (n>1)
out.println(ans);
//else
//out.println(-1);
}
out.flush();
out.close();
}
}

1002 Run

明显搞复杂了,做了一回出题人眼中的“火星人”T_T
平面上的整点就是无法构成正三角形、正五边形、正六边形,没这点见识就只有瞎弄。。。
简化到这个地步,正方形的判断就应该仔细点了吧?四条边及两对角线的长度比较都写上,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
* Nov 19, 2015 7:32:18 PM
* PrjName: hdu5365
* @semprathlon
*/
import java.io.*;
import java.util.*;
public class Main {
static Point[] pt;
static boolean check(Point p1,Point p2,Point p3,Point p4){
double[] v=new double[6];
v[0]=Point.dist(p1, p2);
v[1]=Point.dist(p2, p3);
v[2]=Point.dist(p3, p4);
v[3]=Point.dist(p1, p4);
v[4]=Point.dist(p1, p3);
v[5]=Point.dist(p2, p4);
Arrays.sort(v);
return v[0]==v[1]&&v[1]==v[2]&&v[2]==v[3]&&v[4]==v[5];
}
public static void main(String[] args) throws IOException{
InputReader in=new InputReader(System.in);
PrintWriter out=new PrintWriter(System.out);
while(in.nextLine()!=null){
int n=in.nextInt();
pt=new Point[n];
for(int i=0;i<n;i++)
pt[i]=new Point(in.nextInt(), in.nextInt());
int ans=0;
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
for(int k=j+1;k<n;k++)
for(int l=k+1;l<n;l++){
Point p1=pt[i],p2=pt[j],p3=pt[k],p4=pt[l];
if (check(p1, p2, p3, p4))
ans++;
}
out.println(ans);
}
out.flush();
out.close();
}
}

1003 The mook jong

多么有教育意义的猜公式,猜不出就别偏执了。。。
f[i]=s[i-3]+1,s[i]=s[i-1]+f[i],…

Bestcoder

1001 Untitled

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* 2015年8月1日 下午7:15:14
* PrjName:Bc49-01
* @ Semprathlon
*/
import java.io.*;
import java.util.*;
public class Main {
static ArrayList<Integer> v=new ArrayList<Integer>();
static int[] a,f;
static int lowbit(int x){
return x&(-x);
}
static int get(int x){
int res=0;
while(x>0){
res++;
x-=lowbit(x);
}
return res;
}
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
InputReader in=new InputReader(System.in);
PrintWriter out=new PrintWriter(System.out);
int T=in.nextInt();
while(T-->0){
v.clear();
int n=in.nextInt();
int m=in.nextInt();
for(int i=1;i<=n;i++)
v.add(in.nextInt());
Collections.sort(v);
f=new int[1<<n];
Arrays.fill(f, -1);
f[0]=m;
//out.println(n);
int ans=Integer.MAX_VALUE;
for(int i=0;i<(1<<n);i++)
if (f[i]>0)
for(int j=0;j<n;j++)
if (((1<<j)&i)==0){
int k=i|(1<<j);
f[k]=f[i]%v.get(j);
if (f[k]==0)
ans=Math.min(ans, get(k));
}
if (ans==Integer.MAX_VALUE) out.println(-1);
else out.println(ans);
}
out.flush();
out.close();
}
}

1002 Three Palindromes

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

  • Problem Description
    Can we divided a given string S into three nonempty palindromes?

  • Input
    First line contains a single integer $ T \leq 20 $ which denotes the number of test cases.
    For each test case , there is an single line contains a string S which only consist of lowercase English letters. $ 1\leq |s| \leq 20000 $

  • Output
    For each case, output the “Yes” or “No” in a single line.

  • Sample Input
    2
    abc
    abaadada

  • Sample Output
    Yes
    No

赛时的Hash做法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* 2015年8月1日 下午7:47:15
* PrjName:Bc49-02
* @ Semprathlon
*/
import java.io.*;
import java.util.*;
public class Main {
static long pri=29L;
static long lh(String s,long res,int p){
return res*pri+(long)(s.charAt(p)-'a');
}
static long rh(String s,long res,int p,long m){
return res+(long)(s.charAt(p)-'a')*m;
}
static BitSet v=new BitSet(20010);
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
InputReader in=new InputReader(System.in);
PrintWriter out=new PrintWriter(System.out);
int T=in.nextInt();
while(T-->0){
String s=new String(in.next());
int len=s.length();
//s=s+"#"+(new StringBuffer(s).reverse().toString());
//out.println(s);
boolean ans=false;
long l1=0L,r1=0L,tmp=1L;
for(int i=0;i<len;i++){
if (ans) break;
l1=lh(s, l1, i);
r1=rh(s, r1, i, tmp);
//out.println(i+" "+l1+" "+r1);
tmp*=pri;
//if ((i&1)>0) continue;
if (l1==r1){
//out.println("f"+i);
long l2=0L,r2=0L,tmp2=1L;
v.clear();
for(int j=i+1;j<len;j++){
l2=lh(s,l2,j);
r2=rh(s,r2,j,tmp2);
tmp2*=pri;
//if (((j-i+1)&1)>0) continue;
if (l2==r2) v.set(j);
}

l2=0L;r2=0L;tmp2=1L;
for(int j=len-1;j>i;j--){
l2=lh(s,l2,j);
r2=rh(s,r2,j,tmp2);
tmp2*=pri;
//if (((len-j+1)&1)>0) continue;
if (l2==r2&&v.get(j-1)){
ans=true;break;
}
}
}
}
out.println(ans?"Yes":"No");
}
out.flush();
out.close();
}
}

首次尝试去hack别人不成,还被人黑了,立马TLE

题解介绍的多种方法中,个人认为二分+hash代码量较少,如何实现?

2015 Multi-University Training Contest 5

1009 MZL’s Border

字符串是可递归形式构造的,求解也是递归的;
但是递归时划分的三种情况,最终并没有做好化归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.io.*;
import java.util.*;
import java.math.*;
public class Main{
static BigInteger f[] = new BigInteger[1005];
public static void main(String[] args){
f[1] = new BigInteger("1");
f[2] = new BigInteger("2");
for(int i = 3; i <= 1001; i++)
f[i] = f[i - 1].add(f[i - 2]);
Scanner cin = new Scanner(System.in);
int T = cin.nextInt();
int n;
BigInteger m;
for(int cas = 1; cas <= T; cas++){
n = cin.nextInt();
m = cin.nextBigInteger();
BigInteger mm = m.add(new BigInteger("1"));
int p = 0;
for(int i = 1; i <= 1001; i++){
if(f[i].compareTo(mm) > 0){
p = i;
break;
}
}
BigInteger ans = m.subtract(f[p - 2]);
System.out.println(ans.mod(new BigInteger("258280327")));
}

}
}

2015 Multi-University Training Contest 4

1009 Walk Out

状态压缩方面,虽然想到了用一维的x+y替代二维的x,y,但并没有做到位。
既然可以转化成二维DP,还有何搜索必要
寻找合适的出发点时,不要陷入“极近点”而丢失了“最近点”!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include<cctype>

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<queue>
#include<stack>
#include<set>
#include<map>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int inf=0x7fffffff;
const double eps=1e-3;

typedef pair<int,int> pr;
const int dir[4][2]={ {0,-1},{0,1},{-1,0},{1,0}};
const int maxn=1010;
const int maxm=1010;
int n,m,X0,Y0;
bool g[maxn][maxm],f[maxn][maxm],vis[maxn][maxm];
char str[maxn];

bool can(int x,int y){
if (x<1||x>n||y<1||y>m) return 0;
return 1;
}
bool can(pr p){
return can(p.first,p.second);
}
int mdis(int x,int y){
return abs(x-n)+abs(y-m);
}
int mdis(pr p){
return mdis(p.first,p.second);
}
int geth(pr p){
return p.first+p.second;
}

void find0(int x,int y){
if (vis[x][y]||!can(x,y)) return;
vis[x][y]=1;
if (g[x][y]) return;
f[x][y]=1;
if (x+y>X0+Y0)
{
X0=x;Y0=y;
}
for(int i=0;i<4;i++) find0(x+dir[i][0],y+dir[i][1]);
}


int main()
{
int T;
scanf("%d",&T);
while(T--)
{

scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",str+1);
for(int j=1;j<=m;j++)
{
if (str[j]=='1') g[i][j]=1;
else g[i][j]=0;
}
}

X0=0;Y0=0;
memset(vis[0],0,maxn*maxm*sizeof(vis[0][0]));
memset(f[0],0,maxn*maxm*sizeof(f[0][0]));
find0(1,1);
//cout<<X0<<' '<<Y0<<endl;
if (X0+Y0==n+m){
printf("%d\n",0);
continue;
}
if (X0+Y0<2)
{
X0=1;Y0=1;
f[1][1]=1;
printf("1");
}
for(int i=X0+Y0;i<n+m;i++)
{
int k=1;
for(int j=max(1,i-m);j<=min(n,i-1);j++)
if (f[j][i-j])
{
int k1=j<n?g[j+1][i-j]:1;
int k2=i-j<m?g[j][i-j+1]:1;
k=min(k,min(k1,k2));
}
for(int j=max(1,i-m);j<=min(n,i-1);j++)
if (f[j][i-j])
{
int k1=j<n?g[j+1][i-j]:1;
int k2=i-j<m?g[j][i-j+1]:1;
if (k1==k) f[j+1][i-j]=1;
if (k2==k) f[j][i-j+1]=1;
}
printf("%d",k);
}
puts("");
}
return 0;
}

2015 Multi-University Training Contest 3

1001 Magician

具有肉眼可见的可用线段树解决的统计操作要求。
但是区间更新异常繁杂。
不要拘泥于区间内具体的数据选取,而应该采用状态转移。
除了向上传递操作以外,注意查询操作时不要把区段查询结果直接更新到左右子树上(覆盖区域并不一致)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/**
* 2015年7月29日 上午10:35:39
* PrjName:hdu5316-2
* @ Semprathlon
*/
import java.io.*;
import java.util.*;

public class Main {
final static long inf=0x4000000000000000L;
final static int maxn=100010;
static int[] a=new int[maxn+1];
static SegTree tr=new SegTree(1, maxn);
public static void main(String[] args) {
// TODO Auto-generated method stub
InputReader in=new InputReader(System.in);
PrintWriter out=new PrintWriter(System.out);
int T=in.nextInt();
while(T-->0){
int n=in.nextInt();
int m=in.nextInt();
for(int i=1;i<=n;i++)
a[i]=in.nextInt();
tr.reset(1,1, n, a);
for(int i=1;i<=m;i++){
int k=in.nextInt();
int x=in.nextInt();
if (k==0){
//out.println(tr.query(x, y));
int y=in.nextInt();
long ans=-inf;
long[] res=tr.query(1,x, y);
for(int j=0;j<4;j++)
ans=Math.max(ans, res[j]);
out.println(ans);
}
else{
long y=in.nextLong();
tr.update(1,x, y);
}

}
}
out.flush();
out.close();
}

}

class SegTree{
final static long inf=0x4000000000000000L;
int[] l,r,mid;
long[][] s;
SegTree(int x,int y){
l=new int[(y-x+2)<<2];
r=new int[(y-x+2)<<2];
mid=new int[(y-x+2)<<2];
s=new long[(y-x+2)<<2][4];
build(1,x,y);
}
void build(int k,int x,int y){
/*l=x;r=y;*/mid[k]=(x+y)>>1;
if (x<y){
build(k<<1,x, mid[k]);
build(k<<1|1,mid[k]+1, y);
}
//s0=s1=s2=s3=-inf;
}
void reset(int k,int x,int y,int[] a){
l[k]=x;r[k]=y;mid[k]=(x+y)>>1;
if (x<y){
reset(k<<1,x, mid[k], a);
reset(k<<1|1,mid[k]+1, y, a);
up(s[k],s[k<<1],s[k<<1|1]);
}
else{
if ((mid[k]&1)>0){//odd
s[k][0]=a[mid[k]];
s[k][1]=s[k][2]=s[k][3]=-inf;
}
else{//even
s[k][3]=a[mid[k]];
s[k][0]=s[k][1]=s[k][2]=-inf;
}
}

}
void up(long[] k,long[] l,long[] r){
k[0]=k[1]=k[2]=k[3]=-inf;
k[0]=Math.max(k[0], l[0]+r[2]);//odd-odd
k[0]=Math.max(k[0], l[1]+r[0]);

k[1]=Math.max(k[1], l[1]+r[1]);//odd-even
k[1]=Math.max(k[1], l[0]+r[3]);

k[2]=Math.max(k[2], l[2]+r[2]);//even-odd
k[2]=Math.max(k[2], l[3]+r[0]);

k[3]=Math.max(k[3], l[3]+r[1]);//even-even
k[3]=Math.max(k[3], l[2]+r[3]);

k[0]=Math.max(k[0], l[0]);
k[0]=Math.max(k[0], r[0]);

k[1]=Math.max(k[1], l[1]);
k[1]=Math.max(k[1], r[1]);

k[2]=Math.max(k[2], l[2]);
k[2]=Math.max(k[2], r[2]);

k[3]=Math.max(k[3], l[3]);
k[3]=Math.max(k[3], r[3]);
}
long[] query(int k,int x,int y){
long[] res=new long[4];
if (x==l[k]&&r[k]==y){
res=s[k].clone();
}
else{
long[] L,R;
if (x<=mid[k]) L=query(k<<1,x,Math.min(y, mid[k])).clone();
else L=new long[]{-inf,-inf,-inf,-inf};
if (mid[k]<y) R=query(k<<1|1,Math.max(mid[k]+1, x),y).clone();
else R=new long[]{-inf,-inf,-inf,-inf};
up(res,L,R);
}
return res;
}
void update(int k,int x,long d){
if (l[k]==r[k]){
if ((mid[k]&1)>0){//odd
s[k][0]=d;
s[k][1]=s[k][2]=s[k][3]=-inf;
}
else{//even
s[k][3]=d;
s[k][0]=s[k][1]=s[k][2]=-inf;
}
return;
}
if (x<=mid[k]) update(k<<1,x,d);
if (mid[k]<x) update(k<<1|1,x,d);
up(s[k],s[k<<1],s[k<<1|1]);
}
}

class InputReader{
public BufferedReader reader;
public StringTokenizer tokenizer;

public InputReader(InputStream stream){
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}

public String next(){
while(tokenizer == null || !tokenizer.hasMoreTokens()){
try{
tokenizer = new StringTokenizer(reader.readLine());
}catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}

public int nextInt() {
return Integer.parseInt(next());
}

public long nextLong() {
return Long.parseLong(next());
}
}

1010 Crazy Bobo