敌兵布阵
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4819 Accepted Submission(s): 1922
中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Derek问:“Tidy,马上汇报第3个营地到第10个营地共有多少人!”Tidy就要马上开始计算这一段的总人数并汇报。但敌兵营地的人数经常变动,而Derek每次询问的段都不一样,所以Tidy不得不每次都一个一个营地的去数,很快就精疲力尽了,Derek对Tidy的计算速度越来越不满:"你个死肥仔,算得这么慢,我炒你鱿鱼!”Tidy想:“你自己来算算看,这可真是一项累人的工作!我恨不得你炒我鱿鱼呢!”无奈之下,Tidy只好打电话向计算机专家Windbreaker求救,Windbreaker说:“死肥仔,叫你平时做多点acm题和看多点算法书,现在尝到苦果了吧!”Tidy说:"我知错了。。。"但Windbreaker已经挂掉电话了。Tidy很苦恼,这么算他真的会崩溃的,聪明的读者,你能写个程序帮他完成这项工作吗?不过如果你的程序效率不够高的话,Tidy还是会受到Derek的责骂的.
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
每组数据最多有40000条命令
对于每个Query询问,输出一个整数并回车,表示询问的段中的总人数,这个数最多不超过1000000。
1 10 1 2 3 4 5 6 7 8 9 10 Query 1 3 Add 3 6 Query 2 7 Sub 10 2 Add 6 3 Query 3 10 End
Case 1: 6 33 59
//注意初始化 错了n次
//2887286 2010-08-28 14:46:55 Accepted 1166 46MS 412K 855 B C++ 飞
#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
using namespace std;
int c[50005];
int n;//重要……
void init(){ memset(c,0,sizeof(c));}
int lowbit(int k){return k&-k;}
void add(int k,int d) {for ( ; k <= n ; k += lowbit(k) ) c[k] += d;}
int sum(int k)
{
int s=0;
for(;k>0;k-=lowbit(k)) s+=c[k];
return s;
}
int main()
{
int t,tp=1;
scanf("%d",&t);
while(t--)
{
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int temp;
scanf("%d",&temp);
add(i,temp);
}
string s;
printf("Case %d:/n",tp++);
while(cin>>s , s!="End")
{
int x,y;
scanf("%d%d",&x,&y);
if(s=="Query") printf("%d/n",sum(y)-sum(x-1));
else if(s=="Add") add(x,y);
else if(s=="Sub") add(x,0-y);
}
}
return 0;
}
Minimum Inversion Number
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1036 Accepted Submission(s): 583
For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following:
a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)
You are asked to write a program to find the minimum inversion number out of the above sequences.
10 1 3 6 9 0 8 5 7 4 2
16
//00509749 2010-08-28 15:25:47 Accepted 1003 31 MS 388 KB Visual C++ 飞
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 50001
int c[MAX],n,a[MAX];
void init(){ memset(c,0,sizeof(c));}
int lowbit(int k){return k&-k;}
void modify(int k,int d) {for ( ; k <= n ; k += lowbit(k) ) c[k] += d;}
int getsum(int k)
{
int s=0;
for(;k>0;k-=lowbit(k)) s+=c[k];
return s;
}
int main ()
{
while(scanf("%d", &n) != EOF )
{
init();
int sum = 0 ;
for(int i = 0; i < n; i ++)
scanf("%d", &a[i]);
for(int i = n-1; i >= 0; i --)
{
modify(a[i]+ 1, 1) ;
sum += getsum(a[i]) ;
}
int MIN = sum ;
for(int i = 0; i < n-1; i ++)
{
sum = sum - a[i] + (n - a[i] - 1) ;
if(sum < MIN) MIN = sum ;
}
printf("%d/n", MIN);
}
return 0 ;
}
/*
//归并排序法o(nlogn)
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 50001
typedef int T ;
T num[MAX],a[MAX],sum,b[MAX];//对num 数组从小到大排序,a 为辅助数组
void mergesort(T left,T mid,T right)
{
T i=left,j=mid+1,k=0;
while(i<=mid&&j<=right)
{
if(num[i]<=num[j]) a[k++]=num[i++];
else
{
sum+=mid-i+1;//若加此句并初始化sum=0 则排序后sum 为原序列逆序数
a[k++]=num[j++];
}
}
while(i<=mid) a[k++]=num[i++];
while(j<=right) a[k++]=num[j++];
for(i=left,j=0;i<=right;i++) num[i]=a[j++];
}
void merge(T left,T right)
{ //分治
if(left<right)
{
merge(left,(left+right)/2);
merge((left+right)/2+1,right);
mergesort(left,(left+right)/2,right);
}
}
int main ()
{
int n, i, j, MIN, last ;
while(scanf("%d", &n) != EOF )
{
for(i = 0; i < n; i ++)
{
scanf("%d", &num[i]);
b[i] = num[i] ;
}
sum = 0 ;
merge(0, n-1) ;
MIN = sum ;
for(i = 0; i < n-1; i ++)
{
sum = sum - b[i] + (n - b[i] - 1) ;
if(sum < MIN) MIN = sum ;
}
printf("%d/n", MIN);
}
return 0 ;
}
*/
//本注释代码来自CSDN博客,转载请标明出处:http://blog.csdn.net/yueashuxia/archive/2010/08/01/5781486.aspx
Ping pong
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 713 Accepted Submission(s): 241
Problem Description
N(3<=N<=20000) ping pong players live along a west-east street(consider the street as a line segment).
Each player has a unique skill rank. To improve their skill rank, they often compete with each other. If two players want to compete, they must choose a referee among other ping pong players and hold the game in the referee's house. For some reason, the contestants can’t choose a referee whose skill rank is higher or lower than both of theirs.
The contestants have to walk to the referee’s house, and because they are lazy, they want to make their total walking distance no more than the distance between their houses. Of course all players live in different houses and the position of their houses are all different. If the referee or any of the two contestants is different, we call two games different. Now is the problem: how many different games can be held in this ping pong street?
Input
The first line of the input contains an integer T(1<=T<=20), indicating the number of test cases, followed by T lines each of which describes a test case.
Every test case consists of N + 1 integers. The first integer is N, the number of players. Then N distinct integers a1, a2 … aN follow, indicating the skill rank of each player, in the order of west to east. (1 <= ai <= 100000, i = 1 … N).
Output
For each test case, output a single line contains an integer, the total number of different games.
Sample Input
1
3 1 2 3
Sample Output
1
Source
//2904148 2010-09-01 18:32:49 Accepted 2492 125MS 1040K 1138 B C++ zdg飞
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int c[100005],n,num[100005],_min_l[100005],_max_l[100005],_min_r[100005],_max_r[100005]; //求小于temp的值个数和大于temp的值个数
void init(){ memset(c,0,sizeof(c));}
int lowbit(int k){return k&-k;}
void modify(int k,int d){ for( ;k<=100001;k+=lowbit(k))c[k]+=d;}//WA这里了
int getsum(int k)
{
int s=0;
for(;k>0;k-=lowbit(k)) s+=c[k];
return s;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
init();
for(int i=1;i<=n;i++)
{
modify(num[i],1);
_min_l[i]=getsum(num[i])-1;
}
for(int i=1;i<=n;i++) _max_l[i]=i-_min_l[i]-1;
init();
for(int i=n;i>=1;i--)
{
modify(num[i],1);
_min_r[i]=getsum(num[i])-1;
}
for(int i=n;i>=1;i--)_max_r[i]=(n-i+1)-_min_r[i]-1;
long long ans=0;
for(int i=1;i<=n;i++)
ans += _min_l[i]*_max_r[i] +_max_l[i]*_min_r[i];
cout<<ans<<endl;
}
return 0;
}
See you~
Time Limit: 5000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 965 Accepted Submission(s): 308
Problem Description
Now I am leaving hust acm. In the past two and half years, I learned so many knowledge about Algorithm and Programming, and I met so many good friends. I want to say sorry to Mr, Yin, I must leave now ~~>.<~~. I am very sorry, we could not advanced to the World Finals last year.
When coming into our training room, a lot of books are in my eyes. And every time the books are moving from one place to another one. Now give you the position of the books at the early of the day. And the moving information of the books the day, your work is to tell me how many books are stayed in some rectangles.
To make the problem easier, we divide the room into different grids and a book can only stayed in one grid. The length and the width of the room are less than 1000. I can move one book from one position to another position, take away one book from a position or bring in one book and put it on one position.
Input
In the first line of the input file there is an Integer T(1<=T<=10), which means the number of test cases in the input file. Then N test cases are followed.
For each test case, in the first line there is an Integer Q(1<Q<=100,000), means the queries of the case. Then followed by Q queries.
There are 4 kind of queries, sum, add, delete and move.
For example:
S x1 y1 x2 y2 means you should tell me the total books of the rectangle used (x1,y1)-(x2,y2) as the diagonal, including the two points.
A x1 y1 n1 means I put n1 books on the position (x1,y1)
D x1 y1 n1 means I move away n1 books on the position (x1,y1), if less than n1 books at that position, move away all of them.
M x1 y1 x2 y2 n1 means you move n1 books from (x1,y1) to (x2,y2), if less than n1 books at that position, move away all of them.
Make sure that at first, there is one book on every grid and 0<=x1,y1,x2,y2<=1000,1<=n1<=100.
Output
At the beginning of each case, output "Case X:" where X is the index of the test case, then followed by the "S" queries.
For each "S" query, just print out the total number of books in that area.
Sample Input
2
3
S 1 1 1 1
A 1 1 2
S 1 1 1 1
3
S 1 1 1 1
A 1 1 2
S 1 1 1 2
Sample Output
Case 1:
1
3
Case 2:
1
4
Author
Sempr|CrazyBird|hust07p43
Source
//o(logn*logm) c[n][m]
//2887827 2010-08-28 16:47:18 Accepted 1892 937MS 4140K 2265 B C++ 飞
#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
using namespace std;
const int n=1001;//重要……
int c[n+1][n+1];
void init(){ memset(c,0,sizeof(c));}
int lowbit(int k){return k&(-k);}
void modify(int x,int y,int d)
{
for (int i=x ; i <= n; i += lowbit(i) )
for(int j=y ; j <= n; j += lowbit(j) )
c[i][j] += d;
}
int getsum(int x,int y)
{
int s=0;
for(int i=x ;i > 0; i -= lowbit(i))
for(int j=y ;j > 0; j -= lowbit(j))
s+=c[i][j];
return s;
}
int main()
{
int t,tp=1;
scanf("%d",&t);
while(t--)
{
init();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
modify(i,j,1);
printf("Case %d:/n",tp++);
int m;
scanf("%d",&m);
while(m--)
{
char ch;
cin>>ch;
if(ch=='S')
{
int x11,y11,x22,y22;
scanf("%d%d%d%d",&x11,&y11,&x22,&y22);
x11++;y11++;x22++;y22++;
int x1,y1,x2,y2;
x1=min(x11,x22);x2=max(x11,x22);
y1=min(y11,y22);y2=max(y11,y22);
printf("%d/n",getsum(x2,y2)-getsum(x1-1,y2)-getsum(x2,y1-1)+getsum(x1-1,y1-1));
}
else if(ch=='A')
{
int x,y,d;
scanf("%d%d%d",&x,&y,&d);
x++;y++;
modify(x,y,d);
}
else if(ch=='D')
{
int x,y,d;
scanf("%d%d%d",&x,&y,&d);
x++;y++;
int temp=getsum(x,y)-getsum(x-1,y)-getsum(x,y-1)+getsum(x-1,y-1); //返回单个点的值
if(d>=temp) d=temp;
modify(x,y,-d);
}
else
{
int x1,y1,x2,y2,d;
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&d);
x1++;y1++;x2++;y2++;
int temp=getsum(x1,y1)-getsum(x1-1,y1)-getsum(x1,y1-1)+getsum(x1-1,y1-1); //返回单个点的值
if(d>=temp) d=temp;
modify(x1,y1,-d);
modify(x2,y2,d);
}
}
}
return 0;
}
Stars
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 921 Accepted Submission(s): 348
Problem Description
Astronomers often examine star maps where stars are represented by points on a plane and each star has Cartesian coordinates. Let the level of a star be an amount of the stars that are not higher and not to the right of the given star. Astronomers want to know the distribution of the levels of the stars.
For example, look at the map shown on the figure above. Level of the star number 5 is equal to 3 (it's formed by three stars with a numbers 1, 2 and 4). And the levels of the stars numbered by 2 and 4 are 1. At this map there are only one star of the level 0, two stars of the level 1, one star of the level 2, and one star of the level 3.
You are to write a program that will count the amounts of the stars of each level on a given map.
Input
The first line of the input file contains a number of stars N (1<=N<=15000). The following N lines describe coordinates of stars (two integers X and Y per line separated by a space, 0<=X,Y<=32000). There can be only one star at one point of the plane. Stars are listed in ascending order of Y coordinate. Stars with equal Y coordinates are listed in ascending order of X coordinate.
Output
The output should contain N lines, one number per line. The first line contains amount of stars of the level 0, the second does amount of stars of the level 1 and so on, the last line contains amount of stars of the level N-1.
Sample Input
5
1 1
5 1
7 1
3 3
5 5
Sample Output
1
2
1
1
0
Source
//utility.h
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<fstream>
#include<ctime>
#include<cstdlib>
#include<iomanip>
#include<complex>
#include<stdexcept>
#include<vector>
#include<deque>
#include<list>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<bitset>
#include<algorithm>
#include<numeric>
#define N 32005
using namespace std;
/******************************************************************
树状数组的用处是动态查找前n项和
因为每次yi>=yi-1,所以每次只要求出x<xi的个数就可以了,即前n项和
*******************************************************************/
int C[N];
int LowBit(int x)
{
return x&(x^(x-1));
}
void change(int k,int val)
{
while(k<N)
{
C[k]+=val;
k+=LowBit(k);
}
}
int GetSum(int k)
{
int t=0;
while(k>0)
{
t+=C[k];
k-=LowBit(k);
}
return t;
}
//以上是树状数组的基本操作
int main()
{
//init
int leval[15000];
int n;
while(cin>>n){
fill(C,C+N,0);
fill(leval,leval+15000,0);
int x,y;
for(int i=0;i<n;i++)
{
cin>>x>>y;
leval[GetSum(x+1)]++;
change(x+1,1);
}
for(int j=0;j<n;j++)
cout<<leval[j]<<endl;
}
return 0;
}