Tim's Programming Space  
Tim's Programming Space
日历
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011
统计
  • 随笔 - 20
  • 文章 - 1
  • 评论 - 40
  • 引用 - 0

导航

常用链接

留言簿(3)

随笔档案

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜

 

游戏

 

【题目描述】

lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示。当他使用某种装备时,他只能使用该装备的某一个属性。并且每种装备最多只能使用一次。

游戏进行到最后,lxhgww遇到了终极boss,这个终极boss很奇怪,攻击他的装备所使用的属性值必须从1开始连续递增地攻击,才能对boss产生伤害。也就是说一开始的时候,lxhgww只能使用某个属性值为1的装备攻击boss,然后只能使用某个属性值为2的装备攻击boss,然后只能使用某个属性值为3的装备攻击boss……以此类推。

现在lxhgww想知道他最多能连续攻击boss多少次?

【输入】

输入的第一行是一个整数N,表示lxhgww拥有N种装备

接下来N行,是对这N种装备的描述,每行2个数字,表示第i种装备的2个属性值

【输出】

输出一行,包括1个数字,表示lxhgww最多能连续攻击的次数。

【样例输入】

3

1 2

3 2

4 5

【样例输出】

2

【数据范围】

    对于30%的数据,保证N<=1000

    对于100%的数据,保证N<=1000000


===========================================================================
没什么说的,匈牙利最坏10000^2过了。。其实对于这样随机的边很多的图。。匈牙利的实际运行时间比O(n)多不了多少。。实际测试表明。。比用下面方法的要快。。囧。
官方题解是:10000个点,1000000条边的一个图。对于每个联通块如果是树则只能选到n-1个,那么肯定是选最小的n-1个,如果有环则全部可以。最后for下从1开始哪些可以就行了。。
吐槽:。。。考完回来写匈牙利,写了两遍都错了,而且错的一样。。。调了很久才发现写错的地方,杯具。。

 1 #include <iostream>
 2 #define MAXN 1000010
 3 #define MAXM MAXN*2
 4 
 5 using namespace std;
 6 
 7 int Count = 0;
 8 int begin[MAXN+1], end[MAXM+1], next[MAXM+1];
 9 void AddEdge(int a, int b){
10      Count++;
11      next[Count] = begin[a];
12      begin[a] = Count;
13      end[Count] = b;
14 }
15 
16 int n;
17 #define BUFSIZE 1000000*10
18 char buf[BUFSIZE], *pt = buf;
19 #define scan_int(x) \
20 { \
21   x = 0; \
22   while (!((*pt) >= '0' && (*pt) <= '9')) pt++; \
23   while (((*pt) >= '0' && (*pt) <= '9')) x = x * 10 + (*(pt++)) - '0'; \
24 }
25 void Init(){
26      scanf("%d",&n);
27      int a,b;
28      fread(pt, 1, BUFSIZE, stdin);
29      for (int i = 1; i<=n; i++){
30          //scanf("%d%d",&a,&b);
31          scan_int(a); scan_int(b);
32          AddEdge(a,i);
33          AddEdge(b,i);
34      }
35 }
36 
37 int cnt;
38 int q[MAXN+1];
39 bool hash[MAXN+1];
40 int Link[MAXN+1];
41 bool dfs(int x){
42      for (int now = begin[x]; now; now = next[now])
43          if (!hash[end[now]]){
44             hash[end[now]] = true;
45             q[++cnt] = end[now];
46             if (!Link[end[now]] || dfs(Link[end[now]])){
47                Link[end[now]] = x;
48                return true;
49             }
50          }
51      return false;
52 }
53 
54 void Solve(){
55      int Ans;
56      for (int i = 1; i<=10001; i++){
57          cnt = 0;
58          if (!dfs(i)){
59             Ans = i-1;
60             break;
61          }
62          for (int j = 1; j<=cnt; j++)
63              hash[q[j]] = false;
64      }
65      printf("%d\n",Ans);
66 }
67 
68 int main(){
69     freopen("game.in","r",stdin);
70     freopen("game.out","w",stdout);
71     Init();
72     Solve();
73     return 0;
74 }
75 

posted @ 2010-04-06 20:23 TimTopCoder 阅读(241) | 评论 (0)编辑 收藏
 

幸运数字

 

【题目描述】

在中国,很多人都把68视为是幸运数字!lxhgww也这样认为,于是他定义自己的“幸运号码”是十进制表示中只包含数字68的那些号码,比如68666888都是“幸运号码”!但是这种“幸运号码”总是太少了,比如在[1,100]的区间内就只有6个(6866688688),于是他又定义了一种“近似幸运号码”。lxhgww规定,凡是“幸运号码”的倍数都是“近似幸运号码”,当然,任何的“幸运号码”也都是“近似幸运号码”,比如1216666都是“近似幸运号码”。

现在lxhgww想知道在一段闭区间[a, b]内,“近似幸运号码”的个数。

【输入】

输入数据是一行,包括2个数字ab

【输出】

输出数据是一行,包括1个数字,表示在闭区间[a, b]“近似幸运号码”的个数

【样例输入1

1 10

【样例输出1

2

【样例输入2

1234 4321

【样例输出2

809

【数据范围】

   对于30%的数据,保证1<=a<=b<=1000000

   对于100%的数据,保证1<=a<=b<=10000000000


//================================================================
用容斥原理做。
先造出所有的幸运号码,然后对幸运号码的倍数容斥。
幸运号码有2000+个,为了尽快出解,要加几个剪枝:
1. 如果A是B的倍数,直接去掉。剪掉了一大半。。。

2.从大到小排序,尽快容斥掉一些数。

写的常数稍微少点能进2s了。。

PS :关于中间结果会爆long long的问题。。。从正的爆成负的容易,从正的爆成负的再爆成正的不容易。。。所以猥琐的判大于0。。。

 1#include <iostream>
 2#include <algorithm>
 3#define NNUM 3000
 4#define ll long long
 5
 6using namespace std;
 7
 8ll A,B;
 9void Init(){
10     scanf("%I64d%I64d",&A,&B);
11}

12
13int n = 0;
14ll a[NNUM+1];
15void dfsNum(ll num){
16     if (num > B) return;
17     if (num <= B)
18        a[++n] = num;
19     dfsNum(num * (ll)10 + (ll)6);
20     dfsNum(num * (ll)10 + (ll)8);
21}

22int cnt = 0;
23ll b[NNUM+1];
24
25ll Ans = 0, tmp;
26inline ll gcd(ll a, ll b){
27   while (b)
28         tmp = a, a = b, b = tmp % b;
29   return a;
30}

31
32
33int cmp(const void *a, const void *b){
34    return (*(ll *)b) >  (*(ll *)a) ? 1 : -1;
35}

36
37ll dfs(int pos, ll num){
38   if (pos == n+1return B/num - A/num;
39   ll ret = dfs(pos+1, num);
40   ll newnum = num / gcd(num, a[pos]) * a[pos];
41   if (newnum <= B && newnum >= 1)
42      ret -= dfs(pos+1, newnum);
43   return ret;
44}

45
46void Solve(){
47     dfsNum(6); dfsNum(8);
48     qsort(a+1, n, sizeof(a[0]), cmp);
49     //printf("%d\n",n);
50     for (int i = 1; i<=n; i++){
51         bool boo = true;
52         for (int j = 1; j<=n; j++)
53             if (i!=&& a[i] % a[j] == 0){
54                boo = false;
55                break;
56             }

57         if (boo){
58            a[++cnt] = a[i];
59            //printf("%d %I64d\n", cnt, a[cnt]);
60         }

61     }

62     n = cnt;
63     //printf("%d\n",n);
64     A--;
65     printf("%I64d\n", B - A - dfs(1,1));
66}

67
68int main(){
69    freopen("luckynumber.in","r",stdin);
70    freopen("luckynumber.out","w",stdout);
71    Init();
72    Solve();
73    return 0;
74}

75

posted @ 2010-04-06 20:00 TimTopCoder 阅读(484) | 评论 (2)编辑 收藏
 

timtopcoder.wep.dk

新开的网站,欢迎大家捧场~
posted @ 2010-01-16 15:30 TimTopCoder 阅读(165) | 评论 (0)编辑 收藏
 
     摘要: 最开始写费用流的时候,有且只会SPFA版的费用流,而且一直都够用,一般来说只要建出了图就赢了,网络流怎么都不会超时。。。。。这个情况到今天被终结了。。。终结者见下:-------------------------------------------------------------------------------------------------------- 最优图像 【题目描述】...  阅读全文
posted @ 2010-01-08 18:39 TimTopCoder 阅读(11397) | 评论 (8)编辑 收藏
 
     摘要: 题目叙述:    给出一个有n个节点的树, 一个整数k. 定义dist(u, v)为节点u, v间的距离. 求这棵树中有多少节点对(u, v)满足dist(u, v)<=k. (n<=10000)-------------------------------------------对于这样一个数据范围,显然O(n^2)的直接算是会超时的。大体的思路是:&n...  阅读全文
posted @ 2010-01-05 16:23 TimTopCoder 阅读(2237) | 评论 (5)编辑 收藏
 

This is a reminder of what I need to learn and need to do.

割点和桥
带上下界的网络流:可行流,最大流及其费用流
polya定理
做道要用逆元的题
斯特灵数:第一类,第二类
posted @ 2009-11-30 22:18 TimTopCoder 阅读(107) | 评论 (0)编辑 收藏
 
NOIP2009最后一题。
看到题的时候直接就想到了DancingLinks,但是。。。很后悔是,原来想学的时候觉得难写就没写了。
不过考试时裸搜加最优性剪枝有95分,也很不错了。
DacingLinks其实就是十字链表,用于求解精确覆盖问题:对于一个0-1矩阵,选取一些行使得每列有且只有一个1。
把数独转换为这样一个模型以后就可以用DacingLinks快速的搜索了。
搜索时每次选择1的个数最少的那列,枚举那列上选取的某行,再把那行其他位置有1的列删除,接着继续搜索。回溯时再还原改动。
对于数独而言,一共有9*9个格子,每个格子可以填9个数,所以在0-1矩阵里就有9*9*9=729行,表示在某个格子里填某个数。
同时在某个位置填了某个数后,那个数所在的列,行,9宫格也不能填那个数了,同时那个格子也不能填其他数了,所以某行填某个数有9*9,某列填某个数有9*9,某个9宫格填某个数9*9,某个位置填数9*9,一共就用324列。
建好这样一个图后,就直接用DancingLinks搜索,因为相比一般的裸搜冗余很少,所以速度非常快。
/*
 * $File: sudoku.cpp
 * $Date: Sun Nov 29 20:22:32 2009 CST
 
*/

#include 
<iostream>
#include 
<cstring>
#include 
<cstdio>
#include 
<cstdlib>
#include 
<cmath>

#define LENGTH 9
#define SQRLEN 3
#define MAXN (LENGTH*LENGTH*LENGTH)
#define MAXM (4*LENGTH*LENGTH)
#define MAXNODE MAXN*MAXM

int max(int a,int b){
    
return a>b?a:b;
}
int map[MAXN][MAXM];
int U[MAXNODE],D[MAXNODE],L[MAXNODE],R[MAXNODE];
int S[MAXNODE],C[MAXNODE],ROW[MAXNODE];
int n,m;
int h = 0;//the Leftest and Upest node 
int a[LENGTH][LENGTH];
void Init(){
    freopen(
"sudoku.in","r",stdin);
    freopen(
"sudoku.out","w",stdout);
    
for (int i = 0; i<LENGTH; i++)
        
for (int j = 0; j<LENGTH; j++)
            scanf(
"%d",&a[i][j]);
}
int Row(int x,int y,int num){
    
return (x*LENGTH+y)*LENGTH+num-1;
}

#define SEC_POS 0
#define SEC_ROW 1
#define SEC_COL 2
#define SEC_SQR 3
#define PER_SEC LENGTH*LENGTH

void Fill(int x,int y,int num){
    
int row = Row(x,y,num);
    map[row][SEC_POS
*PER_SEC+x*LENGTH+y] = 1;
    map[row][SEC_ROW
*PER_SEC+x*LENGTH+num-1= 1;
    map[row][SEC_COL
*PER_SEC+y*LENGTH+num-1= 1;
    map[row][SEC_SQR
*PER_SEC+((x/SQRLEN)*SQRLEN+(y/SQRLEN))*LENGTH+num-1= 1;
}
int cnt;
void BuildGraph(){
    
// Build The 0-1 Matrix
    for (int i = 0; i<LENGTH; i++)
        
for (int j = 0; j<LENGTH; j++)
        
if (a[i][j])
                Fill(i,j,a[i][j]);
            
else for (int k = 1; k<=LENGTH; k++)
                Fill(i,j,k);

    
// Build Dacing Links
    n = MAXN,m = MAXM;

    
for (int i = 0; i<n; i++)
        
for (int j = 0; j<m; j++)
            
if (map[i][j])
                map[i][j] 
= ++cnt;
    
int tmp,s = 0,t = 0;
    
for (int i = 0; i<n; i++){
        
for (int j = 0; j<m; j++)
            
if (tmp=map[i][j])
                L[tmp] 
= t, S[tmp] = i,t = tmp;
        
for (int j = m-1; j>=0; j--)
            
if (tmp=map[i][j])
                R[tmp] 
= s, s =tmp;
        R[t] 
= s,L[s] = t;
    }
    
for (int j = 0; j<m; j++){
        t 
= ++cnt;
        
for (int i = 0; i<n; i++)
            
if (tmp=map[i][j])
                U[tmp] 
= t, t = tmp,C[tmp] = cnt, ++S[cnt];
        s 
= cnt;
        
for (int i = n-1; i>=0; i--)
            
if (tmp=map[i][j])
                D[tmp] 
= s, s = tmp;
        D[cnt] 
= s,U[cnt] = t;
    }
    
for (int i = cnt-m+1; i<=cnt; i++)
        L[i] 
= i-1;
    
for (int i = cnt; i>cnt-m; i--)
        R[i] 
= i+1;
    R[h] 
= cnt-m+1,L[h] = cnt;
    L[cnt
-m+1= R[cnt] = h;
}
int ans[MAXM+1];
void Cover(int c){
    L[R[c]] 
= L[c],R[L[c]] = R[c];
    
for (int i = D[c];i!=c;i = D[i])
        
for (int j = R[i];j!=i;j = R[j])
            U[D[j]] 
= U[j],D[U[j]] = D[j],S[C[j]]--;
}
void UnCover(int c){
    
for (int i = U[c];i!=c;i=U[i])
        
for (int j = L[i];j!=i;j = L[j])
            S[C[j]]
++,U[D[j]] = D[U[j]] = j;
    L[R[c]] 
= R[L[c]] = c;
}
int Ans = -1;
int ScoreTable[LENGTH][LENGTH] = {
    {
6,6,6,6,6,6,6,6,6},
    {
6,7,7,7,7,7,7,7,6},
    {
6,7,8,8,8,8,8,7,6},
    {
6,7,8,9,9,9,8,7,6},
    {
6,7,8,9,10,9,8,7,6},
    {
6,7,8,9,9,9,8,7,6},
    {
6,7,8,8,8,8,8,7,6},
    {
6,7,7,7,7,7,7,7,6},
    {
6,6,6,6,6,6,6,6,6}
};
int score(int c){
    
int t = S[c];
    
int num = t%LENGTH+1;
    
int x = t/LENGTH/LENGTH%LENGTH;
    
int y = t/LENGTH%LENGTH;
    
return num*ScoreTable[x][y];
}
int ansmap[LENGTH][LENGTH];
//this function is not used in this program, but it gives out a solution of a sudoku
void GetAns(int step){
    memset(ansmap,
0,sizeof(ansmap));
    
for (int i = 0; i<step; i++){
        
int t = ans[i];
        
int x = t/LENGTH/LENGTH%LENGTH;
        
int y = t/LENGTH%LENGTH;
        
int num = t%LENGTH+1;
        ansmap[x][y] 
= num;
    }
}
void search(int step,int v){
    
if (R[h] == h){
        Ans 
= max(Ans,v);
    
/*    GetAns(step);
        for (int i = 0; i<LENGTH; i++){
            for (int j = 0; j<LENGTH; j++)
                printf("%d ",ansmap[i][j]);
            printf("\n");
        }
        printf("\n");
*/
        
return;
    }
    
int c,s = MAXNODE;
    
for (int i = R[h];i!=h; i=R[i])
        
if (S[i]<s)
            s 
= S[i],c = i;
    Cover(c);
    
for (int i = D[c];i!=c;i=D[i]){
        ans[step] 
= S[i];
        
for (int j = R[i];j!=i;j = R[j])
            Cover(C[j]);
        search(step
+1,v+score(i));
        
for (int j = L[i];j!=i;j = L[j])
            UnCover(C[j]);
    }
    UnCover(c);
}
void DancingLinks(){
    search(
0,0);
    printf(
"%d\n",Ans);
}
void Solve(){
    BuildGraph();
    DancingLinks();
}
int main(){
    Init();
    Solve();
    
return 0;
}

posted @ 2009-11-30 21:52 TimTopCoder 阅读(3493) | 评论 (10)编辑 收藏
 
前两天在yjw神牛和hyf神牛的共同努力下终于学会了后缀数组O(nlogn)倍增构造方法。

构造:
定义s[k][i]表示从s字符串的第i位开始的长度为k的一个字符串(后缀),不够的补零,sa[k][i]表示在所有长度为k的后缀中排序后大小为第i的后缀的位置。显然sa[1]可以直接qsort得到。当sa[k]求到过后,sa[2k]的每个元素都可以O(1)比较得出,这时用桶排,把sa[k]中排名相同的放在一起(放在一个桶里),那么对于每个不同的桶中的元素,他们之间的大小关系就已经确定了,对于同一个桶中的元素,s[2k][i]的前k位是一样的,可能不一样只有后k位,而这个我们是已经得到了的,所以通过sa[k][i]可以算出sa[2k][i-k],桶排把排序过程复杂度降成了O(n),总体构造的复杂度就成了O(nlogn)。DC3算法貌似可以把复杂度降到O(n)...暂时只有膜拜的份了。

现在定义sa[i]为所有后缀排好序后的第i个后缀在原序列中的位置。
定义rank[i]为后缀s[i]在后缀排好序的序列中的排名。
当sa数组求出来了过后,就可以构造h和height数组了。
定义height数组为排好序的后缀中相邻两项的LCP(最常公共前缀),即height[i] = LCP(sa[i],sa[i-1])。
定义h数组为原序列中的某个后缀与排好序的后缀中它的前一个的LCP,即h[i] = LCP(i,sa[rank[i]-1])。

然后有一个hyf和yjw神牛都不知道怎么来的很牛X的定理:h[i]>=h[i-1]-1。。。所以就可以在O(n)时间内直接for出这个h数组来。。。(这步是最诡异也最精髓的,因为没有这个数组后缀数组就没什么用了。。求神牛们讲解下这个定理的证明。。)
求出了h数组后height数组也可以直接得到。

实现方式是用了两个指针轮番上阵,看起来可能会有点纠结。。

应用:
有了h和height数组后,我们就可以用它来做很多事情。但我还不是很熟,只会求一个字符串里面可以相交的最长重复字串的长度。。
cii(uva?)3901 Editor就是这样一道题。
比如abcabcabc的最长重复字串就是abcabc。
其实求出了h和height数组后就变得很简单,就是h或height数组中最大的一个。

欢迎大牛神牛们前来补充和指正!

 1 /*
 2  * $Date: Fri Nov 27 09:00:37 2009 CST
 3  * $File: 3901.cpp
 4  */
 5 #include <iostream>
 6 #include <cstdio>
 7 #include <cstdlib>
 8 #include <cstring>
 9 #include <algorithm>
10 #define MAXLEN 50000
11 
12 using namespace std;
13 
14 char s[MAXLEN+1];
15 bool cmp(const int &a,const int &b){
16     return s[a]<s[b];
17 }
18 
19 int sa[MAXLEN+1],rank[MAXLEN+1],tmp1[MAXLEN+1],tmp2[MAXLEN+1];
20 int h[MAXLEN+1],height[MAXLEN+1];
21 
22 void Solve(){
23     scanf("%s",s);
24     int n = strlen(s);
25     s[n++= 0;
26     for (int i = 0; i<n; i++)
27         sa[i] = i;
28     sort(sa,sa+n,cmp);
29     
30     rank[sa[0]] = 0;
31     for (int i = 1; i<n; i++)
32         if (s[sa[i]]==s[sa[i-1]])
33             rank[sa[i]] = rank[sa[i-1]];
34         else
35             rank[sa[i]] = rank[sa[i-1]]+1;
36 
37     int *s1 = sa,*s2 = tmp1,*= tmp2, *= rank;
38     for (int i = 1; i<n&&r[sa[n-1]]<n-1; i<<=1){
39         //b is the barrel
40         for (int j = 0; j<n; j++)
41             b[r[s1[j]]] = j;
42         for (int j = n-1; j>=0; j--)
43             if (s1[j]>=i)
44                 s2[b[r[s1[j]-i]]--= s1[j]-i;
45         for (int j = n-i; j<n; j++)
46             s2[b[r[j]]] = j;
47         swap(s1,s2);
48         b[s1[0]] = 0;//cause the barrel is now useless, use b as the new rank array
49         for (int j = 1; j<n; j++)
50             if (r[s1[j]]!=r[s1[j-1]]||r[s1[j]+i]!=r[s1[j-1]+i])
51                 b[s1[j]] = b[s1[j-1]]+1;
52             else
53                 b[s1[j]] = b[s1[j-1]];
54         swap(b,r);
55     }
56     //calc 
57     for (int i = 0; i<n; i++){
58         if (r[i] == 0)
59             h[i] = 0;
60         else if (i == 0||h[i-1== 0)
61             for (h[i] = 0; s[i+h[i]]==s[s1[r[i]-1]+h[i]];h[i]++);
62         else 
63             for (h[i]=h[i-1]-1 ; s[i+h[i]]==s[s1[r[i]-1]+h[i]];h[i]++);
64     }
65     int Ans = 1;
66     for (int i = 0; i<n; i++)
67         Ans = max(Ans,h[i]);
68     printf("%d\n",Ans);
69 }
70 int main(){
71     int t;
72     scanf("%d",&t);
73     while (t--)
74         Solve();
75     return 0;
76 }
77 

posted @ 2009-11-27 09:06 TimTopCoder 阅读(1527) | 评论 (0)编辑 收藏
 
     摘要: Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied wit...  阅读全文
posted @ 2009-11-26 19:04 TimTopCoder 阅读(1470) | 评论 (0)编辑 收藏
 
学习某三位神牛。。在cppblog安个家,发点心得体会,一来作为自己的一个复习备忘录,二来给更多的人分享知识~
posted @ 2009-11-26 18:25 TimTopCoder 阅读(165) | 评论 (2)编辑 收藏
仅列出标题
共2页: 1 2 
 
Copyright © TimTopCoder Powered by: 博客园 模板提供:沪江博客