[ZJOI2010 count 数字计数]统计

【题目链接】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1833
【算法分析】
就是从高到低枚举每一位,然后试填比它原位小的数,然后后面的位就可以随便填。这个随便填的话,显然000…000到999…999这一连串中,0-9的数量肯定是一样的。
所以每一位分别+上 (999..999+1)*log (999.999+1)/10。
利用这个快速算,很容易就得解。
【其它】比较繁琐= =,WA了几次。。。
【CODE】
#include #include #include #include using namespace std;
typedef long long lld;
lld L[10];
lld a[10],b[10];
void f(lld x,lld *res){
int i,j,Log=0;
memset(L,0,sizeof(L));
lld mul=1;
while (mul<=x){
mul*=10;
Log++;
}
mul/=10; Log–;
while (mul){
for (i=1;i res[i]+=mul;
for (j=0;j<10;j++){
res[j]+=L[j]*mul;
res[j]+=mul*Log/10;
}
}
L[x/mul%10]++;
mul/=10;
Log–;
if (mul){
for (i=1;i<10;i++){
res[i]+=mul;
for (j=0;j<10;j++)
res[j]+=mul*Log/10;
}
if (x/mul%10){
for (i=0;i<10;i++){
res[i]+=mul*Log/10;
res[i]+=L[i]*mul;
}
res[0]+=mul;
}
}
}
}

int main(){
lld x,y;
cin >> x >> y;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
f(x,a);
f(y+1,b);
for (int i=0;i<10;i++)
cout << b[i]-a[i] << " ";
cout << endl;
}

[ZJOI2010 network 网络扩容]费用流

【题目地址】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1834
【算法分析】
很裸啊。
第一问直接最大流,但是我写得是边权全部为0的费用流= =,方便第二问。。。
第二问的话,就是每条边加多一条容量无限,费用为给定费用的边。
然后加多一个超汇点,n向它连一个maxflow+K的边。
最后输出费用即可。
【其它】1Y,水过留痕。。。
【CODE】
#include #include const int N=1555;
const int E=5555*4;
const int INF=0x7FFFFFFF/2-55;
struct edge{int x,y,c,w;edge *next,*op;}g[E],*ls[N],*fa[N];
int n,m,q,e,flow,cost;
int lx[E],ly[E],lc[E],lw[E],L[N],d[N],v[N];

void add(int x,int y,int c,int w){
g[++e].x=x; g[e].y=y; g[e].c=c; g[e].w=w;
g[e].next=ls[x]; ls[x]=&g[e]; g[e].op=&g[e+1];
g[++e].x=y; g[e].y=x; g[e].c=0; g[e].w=-w;
g[e].next=ls[y]; ls[y]=&g[e]; g[e].op=&g[e-1];
}

void push_back(){
for (int i=2;i<=e;i+=2){
edge *t=&g[i];
t->op->c+=t->c;
t->c=0;
}
}

bool spfa(){
int head=0,tail=1;
for (int i=1;i<=n;i++){
v[i]=0;
d[i]=INF;
}
v[1]=1; d[1]=0; L[1]=1;
while (head!=tail){
head++; if (head>=N) head=0;
for (edge *t=ls[L[head]];t;t=t->next)
if (t->c && d[t->x]+t->w d[t->y]=d[t->x]+t->w;
fa[t->y]=t;
if (!v[t->y]){
v[t->y]=1;
tail++; if (tail>=N) tail=0;
L[tail]=t->y;
}
}
v[L[head]]=0;
}
if (d[n]==INF) return false;
return true;
}

void change(){
int nf=INF;
for (int i=n;i!=1;i=fa[i]->x)
if (fa[i]->c flow+=nf; cost+=d[n]*nf;
for (int i=n;i!=1;i=fa[i]->x){
fa[i]->c-=nf;
fa[i]->op->c+=nf;
}
}

void mincost_maxflow(){
flow=cost=0;
while (spfa()) change();
}

int main(){
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i<=m;i++){
scanf("%d%d%d%d",&lx[i],&ly[i],&lc[i],&lw[i]);
add(lx[i],ly[i],lc[i],0);
}
mincost_maxflow();
printf("%d ",flow);
for (int i=1;i<=m;i++)
add(lx[i],ly[i],INF,lw[i]);
add(n,n+1,flow+q,0);
n++;
push_back();
mincost_maxflow();
printf("%dn",cost);
}

[HDOJ3418 Beautiful Dream]二分答案+判定 or 松弛

【题目大意】
给定n种玩具,他们分别有a[1]…a[n]个,如果一个人获得了m种不同的玩具,那么他就会高兴,问最多能让多少个人高兴。
【算法分析】
算法1:
二分答案,然后把a[i]比答案大的都变成答案。
然后判Sum(a[i])是否大于等于m*ans。如果是则可行,否则不可行。
算法2:
每次求和,然后和/m得到一个上界,然后把a[i]>Sum/m都变成Sum/m。
然后继续求,直到没有a[i]改变。

【其它】
还有O(n)的算法。不过没想出来= =
LCC这有,不过没看懂:http://hi.baidu.com/pojoflcc/blog/item/a5e757816511ccdb9123d9b4.html
然后郭神牛给了个提示,拍个序从大到小搞。能n lg n。
我还是没YY到。。。继续YY一下。想到了更新。
【CODE】
#include using namespace std;
typedef long long lld;
lld n,m,Sum;
lld a[155];

bool can(lld Limit){
Sum=0;
lld i;
for (i=1;i<=n;i++)
if (a[i]>Limit) Sum+=Limit;
else Sum+=a[i];
if (Sum>=m*Limit) return true;
return false;
}

int main(){
lld l,r,mid,i;
while (cin >> n >> m){
for (i=1;i<=n;i++) cin >> a[i];
l=0; r=1000000000*n;
while (l+1 mid=(l+r)/2;
if (can(mid)) l=mid;
else r=mid-1;
}
if (can(r)) l=r;
cout << l << endl;
}
return 0;
}

[Sdoi2010 Hide and Seek]哈密顿距离,45°、135度扫描线、树状数组

【题目链接】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1941
【题目大意】
给出平面上n个点。设Ki表示离i这个点的最远点的距离,与离i这个点的最近点的距离之差。
那么题目就要你求Min(Ki)。
所有距离均为哈密顿距离。
【算法分析】
首先如果我们把一个点作为原点。
那么我们发现哈密顿距离为<=2的是这个形状:
..*..
.***.
*****
.***.
..*..
我们把中间那个当原点,那么我们分开4个象限来YY。
假如说第二象限吧,
显然,哈密顿距离为2的点都在一条直线上,在这之后,哈密顿距离为3的点也都会在一条直线上~。而这条直线的倾斜角都是45°
在这直线上的点都可以表示成x-y=q。q为一个常数。(就是y=kx+b的-b啦。。。)
然后我们可以把一个点的权置为x-y。
先按x坐标从小到大排序,然后搞过来,然后要处理第二象限的话,就是在前面的点里,找y坐标>yi的点里面,x-y最小(大)的。然后这个可以用树状数组解决。
然后其它象限也是类似解决。不过1、3象限是要用倾斜角135°的直线去弄。
【其它】1A,Orz,我承认我用了外挂。。。
1 27780 edward_mj 2856K 1653MS G++ 3.30K 2010-06-04 10:19:22 2 26574 Soiliml 6488K 2386MS Pascal 4.60K 2010-05-28 21:43:28 3 25994 root 2880K 2482MS G++ 2.41K 2010-05-26 19:44:01 4 26188 hyf042 15928K 3185MS G++ 4.51K 2010-05-27 12:56:02 5 26410 jiakai 11128K 4012MS G++ 6.46K 2010-05-28 08:05:09 6 26408 jiakai 11128K 4013MS G++ 6.84K 2010-05-28 08:02:40 7 27723 michael_wind 7696K 4294MS Pascal 4.33K 2010-06-03 21:23:23 8 26405 jiakai 6008K 4310MS G++ 6.13K 2010-05-28 07:57:36 9 26845 zxytim 16184K 4325MS G++ 5.08K 2010-05-30 16:08:56 10 26406 jiakai 6008K 4340MS G++ 6.13K 2010-05-28 07:58:00 11 26209 sonicmisora 16320K 4467MS G++ 4.06K 2010-05-27 14:31:16 12 26208 sonicmisora 16320K 4467MS G++ 5.03K 2010-05-27 14:29:47 13 25996 root 8632K 4560MS G++ 3.03K 2010-05-26 19:44:52 14 26411 zxytim 6396K 4684MS G++ 4.81K 2010-05-28 08:25:29 【CODE】
#include #include #include const int N=500005;
const int INF=0x7FFFFFFF/2-79;
int n;
int ly[N],Qmin[N],Qmax[N];
struct Point{int x,y,max,min;}a[N];

void Read(int &x){
char ch=getchar();
while (!(ch>=’0′ && ch<='9')) ch=getchar();
x=0;
while (ch>=’0′ && ch<='9'){
x=x*10+ch-‘0’;
ch=getchar();
}
}

void input(){
Read(n);
int i;
for (i=1;i<=n;i++){
Read(a[i].x);
Read(a[i].y);
}
for (i=1;i<=n;i++){
a[i].max=-INF;
a[i].min=INF;
}
}

void clr(){
for (int i=1;i<=n;i++){
Qmin[i]=INF;
Qmax[i]=-INF;
}
}

int cmp(const void *A,const void *B){return *((int*)A)-*((int*)B);}
void Lisan(){
for (int i=1;i<=n;i++) ly[i]=a[i].y;
qsort(ly+1,n,sizeof(int),cmp);
}

int Findy(int x){
int l=1,r=n,mid;
while (l mid=(l+r)/2;
if (x>ly[mid]) l=mid+1;
else r=mid;
}
return l;
}

int Getmax(int p){
int res=-INF;
for (int i=p;i;i-=i&-i)
res>?=Qmax[i];
return res;
}

int Getmin(int p){
int res=INF;
for (int i=p;i;i-=i&-i)
res return res;
}

void Insmax(int p,int key){
for (int i=p;i<=n;i+=i&-i)
Qmax[i]>?=key;
}

void Insmin(int p,int key){
for (int i=p;i<=n;i+=i&-i)
Qmin[i]}

inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x if (((Point*)A)->x!=((Point*)B)->x) return ((Point*)A)->x – ((Point*)B)->x;
return ((Point*)B)->y-((Point*)A)->y;
}

void Deal_45(){
int i,y;
qsort(a+1,n,sizeof(Point),cmp45);
clr();
for (i=1;i<=n;i++){
y=n-Findy(a[i].y)+1;
a[i].max=max(a[i].max,a[i].x-a[i].y-Getmin(y));
a[i].min=min(a[i].min,a[i].x-a[i].y-Getmax(y));
Insmax(y,a[i].x-a[i].y);
Insmin(y,a[i].x-a[i].y);
}
clr();
for (i=n;i>=1;i–){
y=Findy(a[i].y);
a[i].max=max(a[i].max,Getmax(y)-(a[i].x-a[i].y));
a[i].min=min(a[i].min,Getmin(y)-(a[i].x-a[i].y));
Insmax(y,a[i].x-a[i].y);
Insmin(y,a[i].x-a[i].y);
}
}

int cmp135(const void *A,const void *B){
if (((Point*)A)->x!=((Point*)B)->x) return ((Point*)A)->x – ((Point*)B)->x;
return ((Point*)A)->y-((Point*)B)->y;
}

void Deal_135(){
int i,y;
qsort(a+1,n,sizeof(Point),cmp135);
clr();
for (i=1;i<=n;i++){
y=Findy(a[i].y);
a[i].max=max(a[i].max,a[i].x+a[i].y-Getmin(y));
a[i].min=min(a[i].min,a[i].x+a[i].y-Getmax(y));
Insmax(y,a[i].x+a[i].y);
Insmin(y,a[i].x+a[i].y);
}
clr();
for (i=n;i>=1;i–){
y=n-Findy(a[i].y)+1;
a[i].max=max(a[i].max,Getmax(y)-(a[i].x+a[i].y));
a[i].min=min(a[i].min,Getmin(y)-(a[i].x+a[i].y));
Insmax(y,a[i].x+a[i].y);
Insmin(y,a[i].x+a[i].y);
}
}

void work(){
Deal_45();
Deal_135();
}

void output(){
int res=INF;
for (int i=1;i<=n;i++)
res printf("%dn",res);
}

int main(){
input();
Lisan();
work();
output();
return 0;
}

[Sdoi2010 古代猪文]师傅说的数论基础、谢天神牛出的题、BT的数论~、Lucas、中国剩余定理

【题目大意】
求G^(Sum(C(n,i))) % 999911659
其中i | n。
【算法分析】
我们来围观999911659这个数字。
首先他是一个素数。其次,它-1以后是一个square free number。
素数有什么性质呢?
那就是a^x = a^(x % phi(p)) (mod p)。其中p是素数。
然后phi(素数)=这个素数-1。
现在问题聚焦成求 Sum(C(n,i)) % 999911658。  其中 i | n
由于那个可爱的999911658是square free number,于是我们将他分解质因数。
发现只有4个素因子,分别是2、3、4679、35617
然后呢?
因为是分解质因数,所以它们都是素数(废话=.=)
我们单独对这4个素因子求Sum(C(n,i)) % p。
于是乎因为p是素数,所以我们来一个Lucas定理,就可以很方便的算出组合数。
当然,期间还要用到我以前说的“不知名定理”(实际上叫“欧拉定理”)。
(不知道的同学看这里:http://hi.baidu.com/edwardmj/blog/item/24c2e52c0133625c4fc2264a.html)
最后呢,我们得出4个同余方程:
X=A1 (mod 2)
X=A2 (mod 3)
X=A3 (mod 4679)
X=A4 (mod 35617)
好嘞,由于mod的都是素数,所以必然它们是两两互质的。
所以直接上中国剩余定理。
不知道的同学可以参照《算法艺术与信息学竞赛》 (黑书)的P231。
当然这里面涉及到的拓展欧几里得算法在黑书里也有,位于P219。
【其它】
这里面有个小技巧,就是由于算组合数时要用到那个阶乘,可以预处理出来。
由于使用了Lucas定理,所以每个阶乘都不会超过要mod的那个数字。
于是只用处理4个数组,它们的长度分别是2、3、4679、35617。
令人激动的是:1A。
更令人激动的是:
1 27533 edward_mj 632K 15MS G++ 2.04K 2010-06-02 21:14:09 2 27541 AekdyCoin 404K 30MS G++ 2.30K 2010-06-02 21:33:18 3 27538 AekdyCoin 456K 30MS G++ 2.78K 2010-06-02 21:27:11 4 27543 AekdyCoin 400K 45MS G++ 2.17K 2010-06-02 21:36:11 5 27546 AekdyCoin 396K 60MS G++ 2.14K 2010-06-02 21:41:21 6 26437 sonicmisora 412K 230MS G++ 1.92K 2010-05-28 10:56:15 7 26483 zxytim 384K 307MS G++ 2.50K 2010-05-28 14:05:33 8 26349 root 1344K 384MS G++ 2.67K 2010-05-27 20:19:52 9 27515 sevenk 348K 762MS G++ 3.55K 2010-06-02 20:48:10 10 26890 AekdyCoin 348K 777MS G++ 3.04K 2010-05-30 20:43:11 11 26886 AekdyCoin 352K 808MS G++ 2.90K 2010-05-30 20:32:14 12 26438 hyf042 844K 929MS G++ 2.69K 2010-05-28 11:05:21 13 26891 AekdyCoin 288K 933MS G++ 3.31K 2010-05-30 20:52:39 当然,师傅由于之前写疵,所以后面那堆是他在疵状态下写的。
前面的是在使用了那个小技巧之后的时间。。。
【CODE】
#include #include #include #include using namespace std;
typedef long long lld;
const int phi=999911658;
int mm=999911659;
const int N=200000;
struct zys{int L[N],Num[N],t;}pz,nz;
int n,G;
lld a[N];
lld JC[5][37777];

void Div(zys &p,int x){
p.t=0;
for (int i=2;i*i<=x;i++)
if (x%i==0){
p.L[++p.t]=i;
p.Num[p.t]=0;
while (x%i==0){
p.Num[p.t]++;
x/=i;
}
}
if (x!=1) {p.L[++p.t]=x; p.Num[p.t]=1;}
}

void makejc(){
int i,j;
for (i=1;i<=4;i++){
JC[i][0]=1;
for (j=1;j<=pz.L[i];j++)
JC[i][j]=JC[i][j-1]*j%pz.L[i];
}
}

lld Pow_mod(lld x,lld cf,int &mod){
if (cf==0) return 1;
lld res=Pow_mod(x,cf/2,mod);
res=res*res%mod;
if (cf%2) res=res*x%mod;
return res;
}

lld Normal_C(int m,int n,int i){
int p=pz.L[i];
return JC[i][m]*Pow_mod(JC[i][n]*JC[i][m-n]%p,p-2,p)%p;
}

lld C(int m,int n,int i){
if (!n) return 1;
int p=pz.L[i];
if (m%p return Normal_C(m%p,n%p,i)*C(m/p,n/p,i)%p;
}

void deal(int sum){
for (int i=1;i<=4;i++)
a[i]=(a[i]+C(n,sum,i))%pz.L[i];
}

void dfs(int dep,int sum){
if (dep>nz.t){
deal(sum);
return;
}
dfs(dep+1,sum);
for (int i=1;i<=nz.Num[dep];i++){
sum*=nz.L[dep];
dfs(dep+1,sum);
}
}

lld exgcd(lld a,lld b,lld &x,lld &y){
if (!b){
x=1; y=0;
return a;
}
lld res=exgcd(b,a%b,x,y),t;
t=x;
x=y;
y=t-a/b*y;
}

void solve(){
lld i,j,Mi,ans=0,p,q,M=phi;
for (i=1;i<=4;i++){
Mi=M/pz.L[i];
exgcd(Mi,pz.L[i],p,q);
ans=(ans+Mi*p*a[i])%M;
}
if (ans<0) ans+=M;
cout << Pow_mod(G,ans,mm) << "n";
}

int main(){
cin >> n >> G;
G%=mm;
if (G==0) {printf("0n"); return 0;}
Div(pz,phi);
Div(nz,n);
makejc();
dfs(1,1);
solve();
return 0;
}