[HNOI2005]虚拟内存

[HNOI2005]虚拟内存

Time Limit:50000MS Memory Limit:165536K
Total Submit:16 Accepted:6
Case Time Limit:5000MS

Description

操作系统中一种重要的存储管理技术就是虚拟内存技术。操作系统中允许进程同时运行,也就是并行。每个进程都有其相对独立的数据块(进程运行的过程中将对其进行读写操作)。理想的情况下,这些数据块都应该存放在内存中,这样才能实现高效的读写操作。但事实上,内存的容量有限,每个进程只能把一部分数据放在内存中,为了解决这个矛盾,提出了虚拟内存技术。
虚拟内存技术的基本原理是:对进程而言,内存空间是无限大的,进程可以随意地读写数据,而对操作系统内部而言,利用外存来模拟扩充的内存空间,进程要求访问某个内存单元时,交由操作系统处理,操作系统首先在内存中查找该单元是否存在,如果存在,查找成功,否则转入外存查找(一定存在于外存中)。
就存储介质的物理性质而言,内存的访问速度相对于外存要快得多,因此对于每个进程来说操作系统应该把那些访问次数较多的数据存放在内存中,而把那些访问次数很少的数据放在外存中。如何选择内存中暂留的数据是一个很值得研究的问题,下面介绍一个内存管理中比较常用的算法:
内存中的数据以页为基本存储单位,进程的读写操作都针对页来进行。实际内存空间被分割成n页,虚拟内存空间的页数往往要多得多。某一时刻,进程需要访问虚存编号为P的页,该算法的执行步骤如下:
a. 首先在内存中查找,如果该页位于内存中,查找成功,转d,否则继续下面的操作;
b. 寻找内存中是否存在空页(即没有装载任何数据页的页面),若有,则从外存中读入要查找页,并将该页送至内存中的空页进行存储,然后转d,否则继续下面的操作;
c. 在内存中寻找一个访问次数最少的页面(如果存在多个页面的访问次数同时为最少,则选取最早读入数据进入内存的那个页面),从外存中读入要查找页,替换该页。
d. 结束
所谓访问次数是指从当前页面进入内存到该时刻被访问的次数,如果该页面以前进入过内存并被其它页面替换,那么前面的访问次数不应计入这个时刻的访问次数中。
你的任务是设计一个程序实现上述算法。
测试数据将会提供m条读写内存的命令,每条命题提供要求访问的虚拟内存页的编号P。你的程序要求能够模拟整个m条命令的全部执行过程,所有的命令是按照输入的先后执行的,最开始的时候内存中的n页全为空。

Input

第1行为n<10000和m<1000000,分别表示内存页数和读写内存命令条数。接下来有m行,其中第i+1行有一个正整数Pi<=10^9,表示第i条读写内存命令需要访问的虚拟内存页的编号。

Output

仅包含一个正整数,表示在整个模拟过程中,在内存中直接查找成功的次数(即上面的算法只执行步骤a的次数)。

Sample Input

Sample Output

Source
很显然是一个模拟题。。
饿。这个应该用一个Hash查找id,用一个Heap保存当前内存的状态的,但我直接用了map,结果慢死囧。。
Code:

#include<cstdio>#include<set>#include<map>#include<utility>#include<queue>#include<iostream>using namespace std;typedef pair<int,int> ii;struct state{ int used,first; bool inQ; state(){} state(int _first):used(1),first(_first),inQ(true){}};map<int,state> id;struct node{ int id,used,first; node(const state&s,int _id) { used=s.used;first=s.first; id=_id; } bool operator<(const node&o)const { if(used!=o.used) return o.used<used; return o.first<first; }};int n,m,Time=0,ans=0;priority_queue<node> Q;void Check(){ while(Q.size()>=n) { node t=Q.top();Q.pop(); if(t.used<id[t.id].used) { t.used=id[t.id].used; Q.push(t); } else { state&s=id[t.id]; s.inQ=false; s.used=1; //cout<<"Out"<<t.id<<endl; break; } }}void Insert(int x){ if(id.count(x)) { state&s=id[x]; if(s.inQ) { //cout<<"Great"<<x<<endl; ans++;s.used++;s.first=Time; } else { Check();s.inQ=true;s.first=Time; Q.push(node(s,x)); } } else { state s(Time); id[x]=s; Check(); Q.push(node(s,x)); } //cout<<"In"<<x<<endl;}int main(){ freopen("in","r",stdin); scanf("%d %d",&n,&m);int x; while(m–) { scanf("%d",&x); Insert(x); ++Time; } cout<<ans<<endl;}

Code:

13 8 11234254

[Ahoi2009]chess 中国象棋

[Ahoi2009]chess 中国象棋

Time Limit:10000MS Memory Limit:65536K
Total Submit:21 Accepted:11
Case Time Limit:1000MS

Description

在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮。
请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧.

Input

一行包含两个整数N,M,中间用空格分开.

Output

输出所有的方案数,由于值比较大,输出其mod 9999973

Sample Input

Sample Output

Hint

除了在3个格子中都放满炮的的情况外,其它的都可以.

100%的数据中N,M不超过100
50%的数据中,N,M至少有一个数不超过8
30%的数据中,N,M均不超过6

Source

Day2
61.187.179.132:8080/JudgeOnline/showproblem
要Dp。。非常的复杂,看Code吧。。累死了。。
Code:

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstdlib>#include<cstring>#include<string>#include<vector>#include<set>#include<queue>#include<map>#define rep(i,n) for(int i=0;i<n;i++)#define For(i,a,b) for(int i=a;i<=b;i++)#define tr(i,x) for(typeof(x.begin()) i=x.begin();i!=x.end();i++)#define all(x) x.begin(),x.end()#define pb push_backusing namespace std;const int inf=~0U>>1;typedef vector<int> vi;typedef vector<vi> vvi;typedef pair<int,int> ii;const int maxn=100+10,mod=9999973;int Dp[2][maxn][maxn],n,m;int C[maxn][maxn]={0};int plus_mod(int&a,int b){ a+=b;return a%=mod;}int multi_mod(int&a,int b){ return a=((long long)a*b)%mod;}void GetC(){ C[0][0]=1; for(int i=1;i<=m;i++) { C[i][0]=C[i][i]=1; for(int j=1;j<i;j++) { C[i][j]=C[i-1][j-1]+C[i-1][j]; C[i][j]%=mod; } }}#define MM(x) memset(x,0,sizeof(x))int main(){ cin>>n>>m;int now=0,next=1; MM(Dp);GetC(); Dp[next][m][0]=1; for(int i=0;i<n;i++) { swap(now,next); MM(Dp[next]); for(int a0=0;a0<=m;a0++) for(int a1=0;a1+a0<=m;a1++) if(Dp[now][a0][a1]) { int x=Dp[now][a0][a1],c; //Dont used Row i plus_mod(Dp[next][a0][a1],x); //Put one if(a0) { c=x; multi_mod(c,C[a0][1]); plus_mod(Dp[next][a0-1][a1+1],c); } if(a1) { c=x; multi_mod(c,C[a1][1]); plus_mod(Dp[next][a0][a1-1],c); } //Put two if(a0>=2) { c=x; multi_mod(c,C[a0][2]); plus_mod(Dp[next][a0-2][a1+2],c); } if(a1>=2) { c=x; multi_mod(c,C[a1][2]); plus_mod(Dp[next][a0][a1-2],c); } if(a0&&a1) { c=x; multi_mod(c,C[a0][1]); multi_mod(c,C[a1][1]); plus_mod(Dp[next][a0-1][a1],c); } } } int ans=0; rep(i,m+1)rep(j,m+1)plus_mod(ans,Dp[next][i][j]); cout<<ans<<endl;}71 3

USACO Telecowmunication

我突然很怀念USACO,去年我A的差不多了就不想A了。。这个月把它A完吧(*^__^*)
这个题目大意nocow上有。。不过我的算法完全是错的居然过了囧。。
很明显是一个最小割的问题,关键是要让字典序最小,
一般来说是要一个个边枚举的删过去的,但是我懒得怎么搞,于是我给每个节点的点权改成了10000+i i表示第i个节点,然后就这样做了。。
结果居然AC了。这数据也太烂了囧。。
Code:

/* PROG: telecow LANG: C++ ID: Tom Chen*/#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstdlib>#include<cstring>#include<string>#include<vector>#include<set>#include<queue>#include<map>#define rep(i,n) for(int i=0;i<n;i++)#define For(i,a,b) for(int i=a;i<=b;i++)#define tr(i,x) for(typeof(x.begin()) i=x.begin();i!=x.end();i++)#define all(x) x.begin(),x.end()#define pb push_backusing namespace std;const int inf=~0U>>1,maxn=200+10;typedef vector<int> vi;struct Edge{ int t,c; Edge*next,*op; Edge(int _t,int _c,Edge* _next):t(_t),c(_c),next(_next){}}*E[maxn]={0};void InsEdge(int s,int t,int c){ E[s]=new Edge(t,c,E[s]); E[t]=new Edge(s,0,E[t]); E[s]->op=E[t];E[t]->op=E[s];}int vs,vt,n,m;int h[maxn],vh[maxn];const int in=0,out=1,off=10000;inline int node(int x,int type){ return x*2+type;}void Init(){ cin>>n>>m>>vs>>vt;vs–;vt–; vs=node(vs,out); vt=node(vt,in); int s,t; rep(i,n) InsEdge(node(i,in),node(i,out),off+i); while(m–) { cin>>s>>t;–s;–t; InsEdge(node(s,out),node(t,in),inf); InsEdge(node(t,out),node(s,in),inf); }}int v;int aug(int no,int m){ if(no==vt) return m; int l=m; for(Edge*i=E[no];i;i=i->next)if(i->c&&h[no]==h[i->t]+1) { int d=aug(i->t,min(l,i->c)); i->c-=d,i->op->c+=d,l-=d; if(!l||h[vs]>=v) return m-l; } int minh=v; for(Edge*i=E[no];i;i=i->next)if(i->c) minh=min(minh,h[i->t]+1); if(!–vh[h[no]]) h[vs]=v;++vh[h[no]=minh]; return m-l;}int CalFlow(){ memset(h,0,sizeof(h)); memset(vh,0,sizeof(vh)); v=n*2;vh[0]=v;int flow=0; while(h[vs]<v) flow+=aug(vs,inf); return flow;}bool Vis[maxn]={0};void dfs(int x){ Vis[x]=true; for(Edge*i=E[x];i;i=i->next)if(i->c&&!Vis[i->t])dfs(i->t);}bool Used(int x){ if (Vis[node(x,in)]&&!Vis[node(x,out)]) return true; return false;}void Work(){ int flow=CalFlow()/off; cout<<flow<<endl; vi Ans; dfs(vs); rep(i,n)if(Used(i)) Ans.pb(i+1); cout<<Ans[0]; for(int i=1;i<Ans.size();i++) cout<<" "<<Ans[i]; cout<<endl;}int main(){ freopen("telecow.in","r",stdin); freopen("telecow.out","w",stdout); Init(); Work();}

SGU 210

210. Beloved Sonstime limit per test: 2 sec.
memory limit per test: 65536 KBinput: standard
output: standard

Once upon a time there lived a king and he had N sons. And the king wanted to marry his beloved sons on the girls that they did love. So one day the king asked his sons to come to his room and tell him whom do they love.

But the sons of the king were all young men so they could not tell exactly whom they did love. Instead of that they just told him the names of the girls that seemed beautiful to them, but since they were all different, their choices of beautiful girls also did not match exactly.

The king was wise. He did write down the information that the children have provided him with and called you, his main wizard.

"I want all my kids to be happy, you know," he told you, "but since it might be impossible, I want at least some of them to marry the girl they like. So please, prepare the marriage list."

Suddenly you recalled that not so long ago the king told you about each of his sons, so you knew how much he loves him. So you decided to please the king and make such a marriage list that the king would be most happy. You know that the happiness of the king will be proportional to the square root of the sum of the squares of his love to the sons that would marry the girls they like.

So, go on, make a list to maximize the king’s happiness.
Input
The first line of the input file contains N — the number of king’s sons (1 ≤ N ≤ 400). The second line contains N integer numbers Ai ranging from 1 to 1000 — the measures of king’s love to each of his sons.

Next N lines contain lists of king’s sons’ preferences — first Ki — the number of the girls the i-th son of the king likes, and then Ki integer numbers — the girls he likes (all potentially beautiful girls in the kingdom were numbered from 1 to N, you know, beautiful girls were rare in those days).
Output
Output N numbers — for each son output the number of the beautiful girl he must marry or 0 if he must not marry the girl he likes.

Denote the set of sons that marry a girl they like by L, then you must maximize the value of

Sample test(s)
Input 4
1 3 2 4
4 1 2 3 4
2 1 4
2 1 4
2 1 4
Output

2 1 0 4
看上去好像是一个最优匹配的问题,可以很显然将所有孩子排个序,然后一个个匹配过去就可以了囧。。
MS那个八中的OJ不能上了囧。。只好A SGU了囧。。
Code:

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstdlib>#include<cstring>#include<string>#include<vector>#include<set>#include<queue>#include<map>#define rep(i,n) for(int i=0;i<n;i++)#define For(i,a,b) for(int i=a;i<=b;i++)#define tr(i,x) for(typeof(x.begin()) i=x.begin();i!=x.end();i++)#define all(x) x.begin(),x.end()#define pb push_backusing namespace std;const int inf=~0U>>1,maxn=400;typedef vector<int> vi;typedef vector<vi> vvi;typedef pair<int,int> ii;vi E[maxn];int Link[maxn],n;bool Vis[maxn]={0};bool dfs(int x){ if(Vis[x]) return false; Vis[x]=true; tr(i,E[x])if(Link[*i]==-1||dfs(Link[*i])) return Link[*i]=x,true; return false;}int A[maxn];bool cmp(const int&a,const int&b){ return A[a]>A[b];}int main(){ //freopen("in","r",stdin); int P[maxn]; cin>>n; rep(i,n)cin>>A[i],P[i]=i; rep(i,n) { int t,x;cin>>t; while(t–)cin>>x,E[i].pb(x-1); } rep(i,n) Link[i]=-1; sort(P,P+n,cmp); rep(i,n) { memset(Vis,0,sizeof(Vis)); dfs(P[i]); } int Ans[maxn]={0}; rep(i,n) Ans[Link[i]]=i+1; rep(i,n) cout<<Ans[i]<<" "; cout<<endl;}

[SCOI2009]游戏

[SCOI2009]游戏

Time Limit:1000MS Memory Limit:165536K
Total Submit:15 Accepted:11

Description

windy学会了一种游戏。
对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应。
最开始windy把数字按顺序1,2,3,……,N写一排在纸上。
然后再在这一排下面写上它们对应的数字。
然后又在新的一排下面写上它们对应的数字。
如此反复,直到序列再次变为1,2,3,……,N。

如:
1 2 3 4 5 6
对应的关系为
1->2 2->3 3->1 4->5 5->4 6->6
windy的操作如下

1 2 3 4 5 6
2 3 1 5 4 6
3 1 2 4 5 6
1 2 3 5 4 6
2 3 1 4 5 6
3 1 2 5 4 6
1 2 3 4 5 6

这时,我们就有若干排1到N的排列,上例中有7排。
现在windy想知道,对于所有可能的对应关系,有多少种可能的排数。

Input

包含一个整数,N。

Output

包含一个整数,可能的排数。

Sample Input

Sample Output

Source

Day1
这道题目很明显就是给你一个N,然后求在和的N的数列中,最小公倍数有几种可能的情况。
很明显如果一个数A=p1^a1*p2^a2*….的话,他能被表达出来的充分必要条件是:
p1^a1+p2^a2+…..<=N这是很好证明的,就不说了。那么很显然就变成一个DP的问题了。
设F(i,j)为第i个素数开始和小于j有多少情况,具体看代码把(*^__^*) 。。这可以说是一道数学问题了。。看来数学学多了也是有好处的囧。。
Code:

#include<iostream>using namespace std;const int maxn=1000+100;bool IsPrime(int p){ if(p==2) return true; if(p%2==0) return false; for(int x=3;x*x<=p;x+=2) if(p%x==0) return false; return true;}int Ps[maxn],cnt=0,n;void GetPrime() //直接写暴力了,懒得写筛法了。。{ for(int x=2;x<=n;x++) if(IsPrime(x)) Ps[cnt++]=x;}typedef long long ll;ll F[maxn][maxn];bool s[maxn][maxn]={0};ll dfs(int pos,int N) //记忆化搜索 pos-cnt的素数,和小于N有多少种情况{ if(pos==cnt&&N>=0) return 1; //边界情况 ll&ans=F[pos][N]; //用引用比较方便 if(s[pos][N]) return ans; ans=0;s[pos][N]=true; for(int x=Ps[pos];x<=N;x*=Ps[pos]) //枚举第pos个素数的幂数 { ans+=dfs(pos+1,N-x); } ans+=dfs(pos+1,N); //如果不选这个素数的话 return ans;}int main(){ cin>>n;GetPrime(); cout<<dfs(0,n)<<endl;}【输出样例一】3【输出样例二】16【数据规模和约定】30%的数据,满足 1 <= N <= 10 。100%的数据,满足 1 <= N <= 1000 。【输入样例一】3【输入样例二】10

[ZJOI2007]最大半连通子图

[ZJOI2007]最大半连通子图

Time Limit:30000MS  Memory Limit:165536K
Total Submit:45 Accepted:14
Case Time Limit:3000MS

Description

Input

第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述。接下来M行,每行两个正整数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。

Output

应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.

Sample Input

6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4

Sample Output

3
3

Hint

对于20%的数据, N ≤18;
对于60%的数据, N ≤10000;
对于100%的数据, N ≤100000, M ≤1000000;
对于100%的数据, X ≤10^8。

Source

爆栈你二大爷啊!!
我晕。搞了半天WA意思就是爆栈啊。。这下没办法了。我弄了数据发现有一个点无论怎么搞都爆栈,C++又不像Pascal能调栈的,难不成自己写一个模拟版dfs囧囧,就这样吧。不去A这题了。。
这道题很明显要强联通缩点,我用的是Tarjan,然后很明显就变成了TAG上的最长路问题,可以DP解决。。
Code(爆栈一个点。我也没办法囧):
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<cstring>
#include<set>
#include<queue>
#define rep(i,n) for(int i=0;i<n;i++)
#define pb push_back
using namespace std;
const int inf=~0U>>1,maxn=100000;
int n,m,mod;
vector<int> E[maxn];
typedef vector<int>::iterator it;
int ord[maxn]={0},low[maxn],stack[maxn],top=0,cnt=0,id[maxn],snt=0;
bool inStack[maxn]={0};
void dfs(int x)
{
ord[x]=low[x]=++cnt;
stack[top++]=x;inStack[x]=true;
for(it i=E[x].begin();i!=E[x].end();++i)
if(!ord[*i])
dfs(*i),low[x]=min(low[x],low[*i]);
else if(inStack[*i])
low[x]=min(low[x],ord[*i]);
if(low[x]==ord[x])
{
int u;do{u=stack[–top];id[u]=snt;inStack[u]=false;}while(u!=x);
snt++;
}
}
struct State
{
int Ans,Num;
State():Ans(0),Num(1){}
void Renew(const State&o)
{
if(o.Ans<Ans)return;
if(o.Ans>Ans){*this=o;return;}
Num+=o.Num;Num%=mod;
}
};
State Dp[maxn];
set<int> Edge[maxn];
typedef set<int>::iterator sit;
int In[maxn]={0},Num[maxn]={0};
int main()
{
//freopen("in","r",stdin);
scanf("%d %d %d",&n,&m,&mod);int s,t;
while(m–)scanf("%d %d",&s,&t),E[s-1].pb(t-1);
rep(i,n)if(!ord[i])dfs(i);
rep(i,n)
{
int own=id[i];Num[own]++;
for(it e=E[i].begin();e!=E[i].end();++e)
if(id[*e]!=own)
Edge[own].insert(id[*e]);
}
rep(i,snt) for(sit e=Edge[i].begin();e!=Edge[i].end();++e) In[*e]++;
queue<int> Q;vector<int> S;
rep(i,snt) if(!In[i]) Q.push(i);
while(Q.size())
{
int t=Q.front();Q.pop();
S.push_back(t);
for(sit i=Edge[t].begin();i!=Edge[t].end();++i)
if(!–In[*i]) Q.push(*i);
}
for(vector<int>::reverse_iterator i=S.rbegin();i!=S.rend();++i)
{
for(sit e=Edge[*i].begin();e!=Edge[*i].end();++e)
Dp[*i].Renew(Dp[*e]);
Dp[*i].Ans+=Num[*i];
}
State Ans;
rep(i,snt) Ans.Renew(Dp[i]);
cout<<Ans.Ans<<endl;
cout<<Ans.Num<<endl;
}

[ZJOI2007]棋盘制作

[ZJOI2007]棋盘制作

Time Limit:20000MS  Memory Limit:165536K
Total Submit:33 Accepted:23
Case Time Limit:10000MS

Description

国际象棋是世界上最古老的博弈游戏之一,和中国的围棋、象棋以及日本的将棋同享盛名。据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方 阵,对应八八六十四卦,黑白对应阴阳。而我们的主人公小Q,正是国际象棋的狂热爱好者。作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好 朋友小W决定将棋盘扩大以适应他们的新规则。
小Q找到了一张由N*M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一。小Q想在这种纸中裁减一部分作为新棋盘,当然,他希望这 个棋盘尽可能的大。不过小Q还没有决定是找一个正方形的棋盘还是一个矩形的棋盘(当然,不管哪种,棋盘必须都黑白相间,即相邻的格子不同色),所以他希望 可以找到最大的正方形棋盘面积和最大的矩形棋盘面积,从而决定哪个更好一些。
于是小Q找到了即将参加全国信息学竞赛的你,你能帮助他么?

Input

第一行包含两个整数N和M,分别表示矩形纸片的长和宽。接下来的N行包含一个N * M的01矩阵,表示这张矩形纸片的颜色(0表示白色,1表示黑色)。

Output

包含两行,每行包含一个整数。第一行为可以找到的最大正方形棋盘的面积,第二行为可以找到的最大矩形棋盘的面积(注意正方形和矩形是可以相交或者包含 的)。

Sample Input

3 3
1 0 1
0 1 0
1 0 0

Sample Output

4
6

Hint

对于20%的数据,N, M ≤ 80
对于40%的数据,N, M ≤ 400
对于100%的数据,N, M ≤ 2000

Source

61.187.179.132:8080/JudgeOnline/showproblem
原来的算法是没有问题,但是写的太沙茶了。首先那玩意根本不是那么递推的,要用到类似单调队列的结构,一层层扫描过去,对每层维护交替的能向上延伸多少,然后用单调队列算出对于每个点来说,往左第一个高度小于它的和往右第一个小于它的同时注意交替性,然后更新答案就可以了。。
细节很要紧,WA了N次囧。。速度鬼慢但长度不到1K,(*^__^*)
更WS的是我原来那个错误的算法居然能过SPOJ上的数据天哪。。我被雷到了。。
Code:
#include<cstdio>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;i++)
using namespace std;
int n,m,MaxS=0,MaxR=0;
const int maxn=2000+10;
int Line[maxn]={0};
int H[maxn]={0};
void ReadLine()
{
int x;
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
if(x!=Line[i])H[i]++;
else H[i]=1;
Line[i]=x;
}
}
void Renew(int a,int b)
{
if(a>b) swap(a,b);
MaxS=max(MaxS,a*a);
MaxR=max(MaxR,a*b);
}
void CalLine()
{
static int L[maxn],R[maxn];
for(int i=1;i<=m;++i)
{
L[i]=i-1;
while(L[i]&&H[L[i]]>=H[i]&&Line[L[i]+1]!=Line[L[i]])
L[i]=L[L[i]];
}
for(int i=m;i>=1;–i)
{
R[i]=i+1;
while(R[i]<=m&&H[R[i]]>=H[i]&&Line[R[i]]!=Line[R[i]-1])
R[i]=R[R[i]];
}
for(int i=1;i<=m;i++) Renew(H[i],R[i]-L[i]-1);
}
int main()
{
scanf("%d %d",&n,&m);
rep(i,n)ReadLine(),CalLine();
cout<<MaxS<<endl<<MaxR<<endl;
}

小猴打架

小猴打架

Time Limit:5000MS  Memory Limit:165536K
Total Submit:30 Accepted:22
Case Time Limit:1000MS

Description

一开始森林里面有N只互不相识的小猴子,它们经常打架,但打架的双方都必须不是好朋友。每次打完架后,打架的双方以及它们的好朋友就会互相认识, 成为好朋友。经过N-1次打架之后,整个森林的小猴都会成为好朋友。
现在的问题是,总共有多少种不同的打架过程。
比如当N=3时,就有{1-2,1-3}{1-2,2-3}{1-3,1-2}{1-3,2-3}{2-3,1-2}{2-3,1-3}六种不同 的打架过程。

Input

一个整数N。

Output

一行,方案数mod 9999991。

Sample Input

4

Sample Output

96

Hint

50%的数据N<=10^3。
100%的数据N<=10^6。

Source

61.187.179.132:8080/JudgeOnline/showproblem
额。首先他们打架的关系是一颗无根树,就有n^(n-2)种情况,还有打架的顺序,是(n-1)!种,乘起来就可以了囧。。
Code:
#include<iostream>
#define rep(i,n) for(int i=0;i<n;i++)
using namespace std;
const int inf=~0U>>1,mod=9999991;
int main()
{
int n;long long ans=1;cin>>n;
rep(i,n-2)ans*=n,ans%=mod;
rep(i,n-1)ans*=i+1,ans%=mod;
cout<<ans<<endl;
}

[SCOI2009]生日礼物

[SCOI2009]生日礼物

Time Limit:10000MS  Memory Limit:165536K
Total Submit:42 Accepted:22
Case Time Limit:1000MS

Description

小西有一条很长的彩带,彩带上挂着各式各样的彩珠。已知彩珠有N个,分为K种。简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即 位置)。某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上。
小布生日快到了,于是小西打算剪一段彩带送给小布。为了让礼物彩带足够漂亮,小西希望这一段彩带中能包含所有种类的彩珠。同时,为了方便,小西希 望这段彩带尽可能短,你能帮助小西计算这个最短的长度么?彩带的长度即为彩带开始位置到结束位置的位置差。

Input

第一行包含两个整数N, K,分别表示彩珠的总数以及种类数。接下来K行,每行第一个数为Ti,表示第i种彩珠的数目。接下来按升序给出Ti个非负整数,为这Ti个彩珠分别出现的 位置。

Output

应包含一行,为最短彩带长度。

Sample Input

6 3
1 5
2 1 7
3 1 3 8

Sample Output

3

Hint

有多种方案可选,其中比较短的是1~5和5~8。后者长度为3最短。
【数据规模】
对于50%的数据, N≤10000;
对于80%的数据, N≤800000;
对于100%的数据,1≤N≤1000000,1≤K≤60,0≤彩珠位置<2^31。

Source

61.187.179.132:8080/JudgeOnline/showproblem
额。。算法是很好想的,就是从小到大枚举每个位置,然后找出每种颜色在它后面的第一个然后取其中最大的那个更新答案。。我早上就想出来了囧。。
一开始我想的算法是NK的。。超的很厉害囧。。
后来我想用一个set来保存所有颜色大于当前位置的最小位置,然后运用set的找最大值和最小值操作,就很方便了。每次看set中的最小值是不是小于当前位置,是的话后移这个值。就是NLogK了。。可惜极限数据要1.6S。还是超时。。
我又优化了一下还是超时,没办法只好先放着了。。
现在突然发现由于最大值肯定是递增的,所以插入的时候更新一下就OK了。真正只需要知道最小值,那么用一个heap就可以了。。为了方便编程我用了priority_queue
Code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<vector>
#include<set>
#include<queue>
#include<map>
#include<ctime>
#define rep(i,n) for(int i=0;i<n;i++)
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
const int inf=~0U>>1,maxn=1000000,maxk=60;
typedef vector<int> vi;
typedef vi::iterator it;
vi A,S[maxk];
int n,k;
void Init()
{
cin>>n>>k;A.resize(n);it nowA=A.begin();
rep(i,k)
{
int t,x;scanf("%d",&t);S[i].resize(t+1);it nowS=S[i].begin();
rep(j,t)scanf("%d",&x),(*nowA++)=(*nowS++)=x;
*nowS++=inf;
}
}
struct cmp
{
bool operator()(const it&a,const it&b)const
{return *a>*b;}
};
void Work()
{
int s=clock();
sort(all(A));
int ans=inf,Max=0;
priority_queue<it,vector<it>,cmp> Q;
rep(i,k)Q.push(S[i].begin()),Max=max(Max,*S[i].begin());
rep(i,n)
{
int t=A[i];
while(*Q.top()<t)
{
it j=Q.top();Q.pop();
Max=max(Max,*++j);
if(Max==inf)break;
Q.push(j);
}
if(Max==inf)break;
ans=min(ans,Max-t);
}
cout<<ans<<endl;
}
int main()
{
//freopen("in","r",stdin);
int s=clock();
Init();
Work();
}