1354: To The Beginning
时间限制: 1 Sec 内存限制: 128 MB Special Judgetype niz = array[1..500] of integer;
var
r, s : niz;
n : integer;
i, K : longint;
rjesenje_tenk : array[1..2*500*500] of integer;
rjesenje_smjer : array[1..2*500*500] of char;
procedure rasporedi( a : niz; n : integer; X, Y : char );
var
index : niz;
i, j, tmp : integer;
begin
for i := 1 to n do
index[i] := i;
for i := 1 to n do
for j := i+1 to n do
if a[j] < a[i] then begin
tmp := a[i]; a[i] := a[j]; a[j] := tmp;
tmp := index[i]; index[i] := index[j]; index[j] := tmp;
end;
for i := 1 to n do
while a[i] > i do begin
a[i] := a[i] - 1;
K := K + 1;
rjesenje_tenk[K] := index[i];
rjesenje_smjer[K] := X;
end;
for i := n downto 1 do
while a[i] < i do begin
a[i] := a[i] + 1;
K := K + 1;
rjesenje_tenk[K] := index[i];
rjesenje_smjer[K] := Y;
end;
end;
begin
readln( n );
for i := 1 to n do
readln( r[i], s[i] );
rasporedi( r, n, 'U', 'D' );
rasporedi( s, n, 'L', 'R' );
writeln( K );
for i := 1 to K do
writeln( rjesenje_tenk[i], ' ', rjesenje_smjer[i] );
end.
1355: Synchronicity
时间限制: 1 Sec 内存限制: 128 MB#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define MAXN 1000000000
using namespace std;
bool flag[5000000];
int prime[5000000];
int main()
{
int n,p,k=0;
scanf("%d%d",&n,&p);
if (p>32000) {if (n==1) printf("%d\n",p); else printf("0\n"); return 0;}
long long ggg=(long long )p*n;
if (ggg>MAXN) {printf("0\n"); return 0;}
if (p==2) {printf("%d\n",n*2);return 0;}
memset(flag,0,sizeof(0)); int tot=0;
for (int i=2; i<=p-1; i++)
{
if (!flag[i]) prime[++tot]=i;
for (int j=1; j<=tot; j++)
{
if (prime[j]*i>33000) break;
flag[prime[j]*i]=1;
if (i%prime[j]==0) break;
}
}
int time;
for (int i=1; i<=MAXN/p; i++)
{
bool f=0;
for (int j=1; j<=tot; j++)
{
if (i%prime[j]==0) {f=1; break;} time++;
}
if (!f) k++;
if (time>70000000) break;
if (k==n) {printf("%d\n",p*i); break;}
}
if (k<n) printf("0\n");
}
1356: Dream Scape
时间限制: 1 Sec 内存限制: 128 MB#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <stack>
#define shit 10007
#define N 1003
using namespace std;
int n,high[N],a[N][N],ans[N][N],lu[N][N],LU[N][N],RD[N][N],rd[N][N],ld[N][N],LD[N][N],ru[N][N];
char sta[N];
void changeLR(int mat[N][N])
{
for (int i=1; i<=n; i++)
for (int j=1; j<=n/2; j++)
swap(mat[i][j],mat[i][n-j+1]);
}
void changeUD(int mat[N][N])
{
for (int i=1; i<=n; i++)
for (int j=1; j<=n/2; j++)
swap(mat[j][i],mat[n-j+1][i]);
}
void get(int mat[N][N])
{
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++)
{
mat[i][j]+=mat[i-1][j]+mat[i][j-1];
mat[i][j]-=mat[i-1][j-1];
mat[i][j]+=shit;
mat[i][j]%=shit;
}
}
void Tab(int x[N][N],int y[N][N])
{
for (int i=1; i<=n; i++) for (int j=1;j<=n; j++) y[i][j]=x[i][j];
}
void solve()
{
for (int j=0; j<=n; ++j) high[j]=0;
for (int i=1; i<=n; ++i)
{
int area=0; stack<int> s;
s.push(0);
for (int j=1; j<=n; ++j) high[j]=high[j]*(a[i][j])+a[i][j];
for (int j=1; j<=n; ++j)
{
while (s.top() && high[s.top()]>high[j])
{
int x=s.top();
s.pop();
int y=s.top();
area-=(j-y-1)*(high[x]-max(high[y],high[j]));
}
area+=high[j];
s.push(j);
ans[i][j]=max(area-1,0) % shit;
}
}
}
int main()
{
scanf("%d",&n);
for (int i=1; i<=n; ++i)
{
scanf("%s",sta);
for (int j=0; j<n; ++j)
a[i][j+1]=(sta[j]=='C');
}
solve();
Tab(ans,rd);
Tab(ans,RD);
get(RD);
changeLR(a);
solve();
Tab(ans,ld);
Tab(ans,LD);
get(LD);
changeUD(a);
solve();
Tab(ans,lu);
Tab(ans,LU);
get(LU);
changeLR(a);
solve();
Tab(ans,ru);
changeUD(a);
changeUD(ru);
changeLR(ld),changeLR(LD);
changeLR(lu),changeUD(lu),changeLR(LU),changeUD(LU);
int lastans=0;
for (int i=1; i<=n; i++)
{
lastans+=((RD[i][n]-RD[i-1][n]+shit)%shit) * LU[i+1][1];
lastans%=shit;
lastans+=((RD[n][i]-RD[n][i-1]+shit)%shit) * LU[1][i+1];
lastans%=shit;
for (int j=1; j<=n; j++)
{
lastans-=(rd[i][j]*LU[i+1][j+1])%shit,lastans+=shit,lastans%=shit;
lastans-=(ru[i][j]*LD[i-1][j+1])%shit,lastans+=shit,lastans%=shit;
}
}
printf("%d\n",lastans);
}
NOIP2013 Day1
命题学校:衡阳市第八中学
命题人:LMZ(真是对不起ZY了哈)
To The Beginning
1. X0%算法:暴力,祝好运!
2. 100%算法:首先我们可以知道最优方案中,树的移动路线一定不会相交,否则我们交换相交的两棵树剩余的移动路线即可。
接下来该如何考虑呢?
我们需要使每行每列有且仅有一棵树,也就是说,没有任意两棵树出在同一行或同一列。移动方案中会涉及到树的水平移动或竖直移动。并且我们发现,对于任意一个方案,我们可以先进行所有的水平移动,然后进行所有的竖直移动,效果是一样的。 那么,水平移动和竖直移动之间有什么联系吗?答案是:没有任何联系!
于是,我们分别考虑水平移动和竖直移动即可。换言之,我们首先忽视同一列树之间的区别,将树移动到n列,这个过程可以用一个简单的贪心算法达到最优;然后将树按同样的算法移动到n行即可。
时间复杂度:贪心:O(n) 输出:O(n2)
Synchronicity
1. 60%算法:暴力枚举p的倍数,祝大家拿分愉快,时间复杂度O(p-1)
2. X0%算法:加上隐藏分数(输出0),祝大家拿分愉快。
3. 100%算法:开始找规律---发现循环节
设C为<=P的质数的积,由于P不大,C只是百万级的,硬统计C内有多少个符合要求,设符合要求的个数为c,则答案为((N-1)/c)*C+a[(N-1)%c+1],其中a[i]为第i个符合要求的数,现证明其正确性。
我们认为,若i合法,则C+i合法。
现反设C+i非法,则存在p<P满足p|C+i,因为C为<=P的质数的积,所以p|C,所以p|i,与假设矛盾,得证。
Dream Scape
1. 10%算法:暴力,复杂度O(n6)。写得好一点的话可以写到20分。如果有人写成O(n8)那我也没办法了……
2. X0%算法:我们考虑最终选出的两个黑暗矩形(以下简称为矩形)的位置关系,只可能有以下三种情况:既没有公共行也没有公共列,有公共行没有公共列,没有公共行有公共列。很显然,我们一定可以用一列或者一行将两个矩形隔开。 我们首先枚举每一行,计算底边在这一行的矩形的数量与顶边低于这一行的矩形的数量的乘积。然后枚举每一列,计算右边在这一列的矩形数量与左边在此列右边的矩形数量的乘积。这样的话,对于上述三种情况,case1会被计算两次,case2和case3都只会被计算一次。那么,我们再枚举每个点分别作为矩形的右下角和左下角时,计算case1的方案数,做差即可。 那么,如何快速计算方案数呢? 我们考虑计算每个点作为左上、右上、左下、右下四个区域的矩形数量。那么很容易通过简单的算术运算求出以上需要的方案数了。
之后就爆发出你们各种矩阵DP和暴力的优化以及乱搞的精神吧!
3. 100%算法:下面以计算每个点作为左上的矩形的数量。我们首先O(n2)预处理出每行的每个点向右至多延伸多少个黑色格子。对于点(i,j),记其数量为r(i,j)。那么,以点(i,j)为左上角的矩形数量=∑min(r(k, j), r(i,j))(i<=k<=n)。我们对每一列单独处理。考虑第j列时,我们从第n行枚举到第1行,用一个单调队列维护第i行到第n行的第j列的r(k,j)。每次若r(i,j)比队列头的r(i+1,j)大则直接将r(i,j)插入队列并记录出现1次;否则连续弹出队列头直到小于r(i,j),过程中记录弹出的次数,加1即为r(i,j)出现的次数。再用一个部分和计数即可。容易证明这样做是O(n)的。 类似的方法计算出每个点作为矩形的四个顶点的矩形数量。然后计算前缀和。算出答案就比较容易了。
时间复杂度:O(n2)