2015-07-07解题报告、2015-07-09解题报告
三道一眼题,原来应该AK的,结果爆炸了
T1:
①统计有多少个数是负数,若有偶数个不管负数,奇数个尽量把最大的负数的变为0;不行的话尽量把最小的负数变得尽量大,然后转⑦
②尽量把0变为1,否则输出0退出
③尽量把1变为2,否则转⑦
④尽量把2变为3,否则转⑦
⑤增加m/3个3,然后m=m%3
⑥如果m=1,给最小的正数+1;如果m=2,增加一个2
⑦统计每种数有多少个,直接快速幂
统计数的个数有多少个时直接计数即可
复杂度O(T*20000*logM)
考试时候错的代码。。。一个小小的错误。。
统计负数时for(i=0;i<=9999;i++)if(ws[i])fs+=ws[i]写成for(i=0;i<=9999;i++)if(ws[i])fs++;
结果就0分了,~~~~(>_<)~~~~
#include<cstdio>
#include<cstring>
#define MOD 1000000007
long long m,x,T,u,n,w,fs,i,now,ws[22222];
bool ff;
void get(){
long long ans=1,now;
for(long long i=0;i<=20000;i++){
now=i-10000;
for(w=ws[i];w;w>>=1){
if(w&1)ans=(ans*now)%MOD;
now=(now*now)%MOD;
}
}
printf("Case %lld: %lld\n",u,ans);
}
int main(){
freopen("maximum.in","r",stdin);
freopen("maximum.out","w",stdout);
scanf("%lld",&T);
for(u=1;u<=T;u++){
scanf("%lld%lld",&n,&m);
memset(ws,0,sizeof(ws));
for(i=1;i<=n;i++){
scanf("%lld",&x);
ws[x+10000]++;
}
ff=fs=0;
for(i=0;i<=9999;i++)if(ws[i])fs++;
if(fs&1){
for(i=9999;i;i--)if(ws[i])break;
now=i-10000;
if(m<=-now){
ws[now+10000]--;
now+=m;
ws[now+10000]++;
ff=1;
}else{
ws[now+10000]--;
m+=now;
now=0;
ws[now+10000]++;
}
}
if(ff){get();continue;}
now=ws[10000];
if(m<now){
ws[10000]-=m;
ws[10001]+=m;
get();
continue;
}else{
ws[10001]+=ws[10000];
m-=ws[10000];
ws[10000]=0;
}
now=ws[10001];
if(m<now){
ws[10001]-=m;
ws[10002]+=m;
get();
continue;
}else{
ws[10002]+=ws[10001];
m-=ws[10001];
ws[10001]=0;
}
now=ws[10002];
if(m<now){
ws[10002]-=m;
ws[10003]+=m;
get();
continue;
}else{
ws[10003]+=ws[10002];
m-=ws[10002];
ws[10002]=0;
}
ws[10003]+=(m/3);
m%=3;
if(m==2)ws[10002]++;else
if(m==1){
for(i=10000;i<=20000;i++)if(ws[i]){
ws[i]--;
ws[i+1]++;
break;
}
}
get();
}
fclose(stdin);fclose(stdout);
return 0;
}
正确的代码:
#include<cstdio>
#include<cstring>
#define MOD 1000000007
long long m,x,T,u,n,w,fs,i,now,ws[22222];
bool ff;
void get(){
long long ans=1,now;
for(long long i=0;i<=20000;i++){
now=i-10000;
for(w=ws[i];w;w>>=1){
if(w&1)ans=(ans*now)%MOD;
now=(now*now)%MOD;
}
}
printf("Case %lld: %lld\n",++u,ans);
}
int main(){
scanf("%lld",&T);
while(T--){
scanf("%lld%lld",&n,&m);
memset(ws,0,sizeof(ws));
for(i=1;i<=n;i++){
scanf("%lld",&x);
ws[x+10000]++;
}
ff=fs=0;
for(i=0;i<=9999;i++)if(ws[i])fs+=ws[i];//考试时候写成for(i=0;i<=9999;i++)if(ws[i])fs++;,结果全错了QAQ
if(fs&1){
for(i=9999;i;i--)if(ws[i])break;
now=i-10000;
if(m<=(-now)){
ws[now+10000]--;
now+=m;
ws[now+10000]++;
ff=1;
}else{
ws[now+10000]--;
m+=now;
now=0;
ws[now+10000]++;
}
}
if(ff){get();continue;}
ff=0;
for(i=10000;i<=20000;i++)if(ws[i]){ff=1;break;}
now=ws[10000];
if(m<now){
ws[10000]-=m;
ws[10001]+=m;
get();
continue;
}else{
ws[10001]+=ws[10000];
m-=ws[10000];
ws[10000]=0;
}
now=ws[10001];
if(m<now){
ws[10001]-=m;
ws[10002]+=m;
get();
continue;
}else{
ws[10002]+=ws[10001];
m-=ws[10001];
ws[10001]=0;
}
now=ws[10002];
if(m<now){
ws[10002]-=m;
ws[10003]+=m;
get();
continue;
}else{
ws[10003]+=ws[10002];
m-=ws[10002];
ws[10002]=0;
}
if(m>=3)ff=1;
ws[10003]+=(m/3);
m%=3;
if(m==2)ws[10002]++;else
if(m==1&ff){
for(i=10000;i<=20000;i++)if(ws[i]){
ws[i]--;
ws[i+1]++;
break;
}
}
get();
}
}
T2:
很容易写出dp方程:dp[i][j]=min(dp[i-1][k]+abs(k-j))+val[i][j]
然后发现这是单调的,如果从左边转移到右边,只需顺序维护dp[i-1][j]+n-j+1的最小值即可,则dp[i][j]=min(dp[i][j],now-(n-j+1)+val[i][j])
如果从右边转移到左边,只需逆序维护dp[i-1][j]+j的最小值即可,dp[i][j]=min(dp[i][j],now-j+val[i][j])
时间复杂度从O(Tmn^2)降为O(Tmn)
#include<cstdio>
#include<cstring>
#define inf 1e16
long long T,m,n,x,i,j,now,ans,dp[55][2222],wz[55][2222],val[55][2222],a[55][2222];
long long abs(long long x){if(x<0)return -x;return x;}
long long min(long long x,long long y){if(x<y)return x;return y;}
int main(){
freopen("dragonball.in","r",stdin);
freopen("dragonball.out","w",stdout);
scanf("%lld",&T);
while(T--){
memset(val,0,sizeof(val));
scanf("%lld%lld%lld",&m,&n,&x);
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
scanf("%lld",&wz[i][j]);
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
scanf("%lld",&a[i][j]);
for(i=1;i<=m;i++)
for(j=1;j<=2*n;j++)
val[i][j]=dp[i][j]=inf;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++){
val[i][wz[i][j]]=min(val[i][wz[i][j]],a[i][j]);
if(i==1)dp[i][wz[i][j]]=val[i][wz[i][j]]+abs(x-wz[i][j]);
}
for(i=2;i<=m;i++){
now=inf;
for(j=2*n;j;j--){
if(dp[i-1][j]+j<=now)now=dp[i-1][j]+j;
if(now-j+val[i][j]<dp[i][j])dp[i][j]=now-j+val[i][j];
}
now=inf;
for(j=1;j<=2*n;j++){
if(dp[i-1][j]+(n-j+1)<=now)now=dp[i-1][j]+(n-j+1);
if(now-(n-j+1)+val[i][j]<dp[i][j])dp[i][j]=now-(n-j+1)+val[i][j];
}
}
ans=inf;
for(i=1;i<=2*n;i++)if(dp[m][i]<ans)ans=dp[m][i];
printf("%lld\n",ans);
}
fclose(stdin);fclose(stdout);
return 0;
}
T3:
枚举每条边,对所有点暴力宽搜一遍,时间复杂度O(nm^m),考试时T了5个点。。
#include<cstdio>
#include<cstring>
#define N 111
#define M 6666
#define inf 1e9
int n,m,i,j,x,y,now,tot,head,tail,ans,last[M],next[M],first[N],dis[N],q[N];
bool v[N],ff;
void ins(int x,int y){last[++tot]=y;next[tot]=first[x];first[x]=tot;}
int main(){
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
scanf("%d%d",&n,&m);tot=1;
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
ins(x,y);ins(y,x);
}
for(now=1;now<=m;now++){
ff=0;ans=0;
for(j=1;j<=n;j++){
memset(v,0,sizeof(v));
for(i=1;i<=n;i++)dis[i]=inf;
head=0;tail=1;q[1]=j;dis[j]=0;v[j]=1;
while(head<tail)
for(i=first[x=q[++head]];i;i=next[i])if(now!=(i>>1)){
int y=last[i];
if(!v[y]){
v[y]=1;
dis[y]=dis[x]+1;
q[++tail]=y;
}
}
for(i=1;i<=n;i++)if(dis[i]==inf){ff=1;break;}else ans+=dis[i];
if(ff)break;
}
if(ff)puts("INF");else printf("%d\n",ans);
}
fclose(stdin);fclose(stdout);
return 0;
}
然后用了小数据对拍会出错的贪心,结果A了、、
#include<cstdio>
#include<cstring>
#define N 111
#define M 6666
#define inf 1e9
int n,m,i,j,x,y,now,tot,head,tail,sum,ans1,ans2,S,T,uu,last[M],next[M],first[N],dis[N][N],dis2[N],q[N];
bool v[N],ff;
void ins(int x,int y){last[++tot]=y;next[tot]=first[x];first[x]=tot;}
int main(){
scanf("%d%d",&n,&m);tot=1;
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
ins(x,y);ins(y,x);
}
for(j=1;j<=n;j++){
memset(v,0,sizeof(v));
for(i=1;i<=n;i++)dis[j][i]=inf;
head=0;tail=1;q[1]=j;dis[j][j]=0;v[j]=1;
while(head<tail)
for(i=first[x=q[++head]];i;i=next[i]){
int y=last[i];
if(!v[y]){
v[y]=1;
dis[j][y]=dis[j][x]+1;
q[++tail]=y;
}
}
for(i=1;i<=n;i++)sum+=dis[j][i];
}
for(now=1;now<=m;now++){
ff=0;ans1=ans2=0;
S=last[now*2];
T=last[now*2+1];
memset(v,0,sizeof(v));
for(i=1;i<=n;i++)dis2[i]=inf;
head=0;tail=1;q[1]=S;dis2[S]=0;v[S]=1;
while(head<tail)
for(i=first[x=q[++head]];i;i=next[i])if(now!=(i>>1)){
int y=last[i];
if(!v[y]){
v[y]=1;
dis2[y]=dis2[x]+1;
q[++tail]=y;
}
}
for(i=1;i<=n;i++)if(dis2[i]==inf){ff=1;break;}else if(dis2[i]!=dis[S][i])ans1++;
memset(v,0,sizeof(v));
for(i=1;i<=n;i++)dis2[i]=inf;
head=0;tail=1;q[1]=T;dis2[T]=0;v[T]=1;
while(head<tail)
for(i=first[x=q[++head]];i;i=next[i])if(now!=(i>>1)){
int y=last[i];
if(!v[y]){
v[y]=1;
dis2[y]=dis2[x]+1;
q[++tail]=y;
}
}
for(i=1;i<=n;i++)if(dis2[i]==inf){ff=1;break;}else if(dis2[i]!=dis[T][i])ans2++;
if(dis2[S]!=1)ans1++,ans2++;
uu=sum+ans1*ans2*(dis2[S]-dis[S][T])-(dis2[S]-dis[S][T])*2;
if(uu&1)uu++;
if(ff)puts("INF");else printf("%d\n",uu);
}
}
2015-07-09
T1:似乎是基础题,但是从来没有做过,怎么弄应该都能过吧
#include<cstdio>
#include<algorithm>
#define N 3333
using namespace std;
int n,p,i,sz,a[N],pos[N];
struct EG{int v,id,h;}b[N];
bool cmp(EG a,EG b){return a.h<b.h||(a.h==b.h&&a.id<b.id);}
void find(int l1,int r1,int l2,int r2,int high){
if(l1>r1||l2>r2)return;
b[l2].id=++sz;b[l2].h=high;
if(l1==r1||l2==r2){printf("%d ",b[l2].v);return;}
find(l1,pos[b[l2].v]-1,l2+1,l2+pos[b[l2].v]-l1,high+1);
find(pos[b[l2].v]+1,r1,l2+pos[b[l2].v]-l1+1,r2,high+1);
printf("%d ",b[l2].v);
}
void find2(int l1,int r1,int l2,int r2,int high){
if(l1>r1||l2>r2)return;
b[r2].id=++sz;b[r2].h=high;
if(l1==r1||l2==r2){printf("%d ",b[r2].v);return;}
printf("%d ",b[r2].v);
find2(l1,pos[b[r2].v]-1,l2,l2+pos[b[r2].v]-l1-1,high+1);
find2(pos[b[r2].v]+1,r1,l2+pos[b[r2].v]-l1,r2-1,high+1);
}
int main(){
scanf("%d%d",&n,&p);
for(i=1;i<=n;i++)scanf("%d",&a[i]),pos[a[i]]=i;
for(i=1;i<=n;i++)scanf("%d",&b[i].v);
if(p==1)find(1,n,1,n,1);else find2(1,n,1,n,1);
puts("");
sort(b+1,b+n+1,cmp);
for(i=1;i<=n;i++)printf("%d ",b[i].v);
}
T2:看到题目直接做了,以为就是傻逼拓扑排序,结果和HZH对拍的时候发现T了,原来n=50000
那么把度为0的点加入堆,每次选序号最小的就行了,变成O(nlgn+m)
#include<cstdio>
#include<iostream>
#define N 55555
#define M 1111111
using namespace std;
int n,m,x,y,i,ans,tot,root,last[M],next[M],first[N],du[N],stack[N],son[N][2];
bool f,v[N];char ch;
void ins(int x,int y){last[++tot]=y;next[tot]=first[x];first[x]=tot;}
void read(int &x){
for(ch=getchar();ch<'0';ch=getchar());
for(x=0;ch>='0';ch=getchar())x=x*10+ch-'0';
}
int merge(int x,int y){
if(!x||!y)return x+y;
if(x>y)swap(x,y);
son[x][1]=merge(son[x][1],y);
swap(son[x][0],son[x][1]);
return x;
}
int main(){
read(n);read(m);
for(i=1;i<=m;i++){
read(x);read(y);
du[y]++;ins(x,y);
}
for(i=1;i<=n;i++)if(!du[i])root=merge(root,i);
while(root){
x=root;
stack[++ans]=x;
root=merge(son[root][0],son[root][1]);
for(i=first[x];i;i=next[i]){
du[last[i]]--;
if(!du[last[i]])root=merge(root,last[i]);
}
}
if(ans!=n)puts("No Answer!");else for(i=1;i<=n;i++)printf("%d ",stack[i]);
}
T3:8年前ZJOI的原题,当年ZJOI还是那么简单,还会考斜率优化这种最基础的东西,现在都的题已经没法做了
设sum[i]=Σp[i]*x[i],sump[i]=Σp[i]
dp[i]=min(dp[j]+sum[j]-x[i]*sump[j]-(sum[i]-x[i]*sump[i])+c[i]),然后就是斜率优化裸题啦
#include<cstdio>
#define N 1000500
char ch;long long f[N],x[N],c[N],sum[N],sump[N],p[N],q[N],i,j,n,h,t;
void read(long long &x){
for(ch=getchar();ch<'0';ch=getchar());
for(x=0;ch>='0';ch=getchar())x=x*10+ch-'0';
}
long long getx(int i,int j){return f[i]+sum[i]-f[j]-sum[j];}
long long gety(int i,int j){return sump[i]-sump[j];}
int main(){
freopen("storage.in","r",stdin);
freopen("storage.out","w",stdout);
read(n);
for(i=1;i<=n;i++){
read(x[i]);read(p[i]);read(c[i]);
sum[i]=sum[i-1]+x[i]*p[i];
sump[i]=sump[i-1]+p[i];
}
t=1;
for(i=1;i<=n;i++){
while(h<t&&getx(q[h+1],q[h])<x[i]*gety(q[h+1],q[h]))h++;
f[i]=f[q[h]]+sum[q[h]]-x[i]*sump[q[h]]+x[i]*sump[i]-sum[i]+c[i];
while(h<t&&getx(q[t],i)*gety(q[t-1],q[t])<=getx(q[t-1],q[t])*gety(q[t],i))t--;
q[++t]=i;
}
printf("%lld",f[n]);
}
2015年7月08日 15:02
每天贪心写写很自豪么。
2015年7月08日 20:58
每天贪心写写很自豪么。
2015年7月09日 10:26
每天贪心写写很自豪么。
2015年7月09日 10:45
每天贪心写写很自豪么。
2015年7月09日 10:51
每天贪心写写很自豪么。
2015年7月09日 10:51
每天贪心写写很自豪么。
2015年7月09日 10:52
每天贪心写写很自豪么。
2015年7月09日 10:52
每天贪心写写很自豪么。
2015年7月09日 10:54
每天贪心写写很自豪么。
2015年7月09日 11:00
每天贪心写写很自豪么。
2015年7月09日 11:01
每天贪心写写很自豪么。
2015年7月09日 11:01
每天贪心写写很自豪么。
2015年7月09日 11:02
每天贪心写写很自豪么。
2015年7月09日 11:02
每天贪心写写很自豪么。
2015年7月09日 11:02
每天贪心写写很自豪么。
2015年7月09日 22:26
每天贪心写写很自豪么。
2015年7月09日 22:27
每天贪心写写很自豪么。
2015年7月09日 22:27
每天贪心写写很自豪么。
2015年7月09日 22:28
每天贪心写写很自豪么。
2015年7月09日 22:28
每天贪心写写很自豪么。
2015年7月09日 22:28
每天贪心写写很自豪么。
2015年7月09日 22:29
每天贪心写写很自豪么。
2015年7月09日 22:29
每天贪心写写很自豪么。
2015年7月09日 22:29
每天贪心写写很自豪么。
2015年7月09日 22:30
每天贪心写写很自豪么。
2015年7月09日 22:30
每天贪心写写很自豪么。
2015年7月09日 22:30
每天贪心写写很自豪么。
2015年7月09日 22:31
每天贪心写写很自豪么。
2015年7月09日 22:31
每天贪心写写很自豪么。
2015年7月09日 22:31
每天贪心写写很自豪么。
2015年7月09日 22:32
每天贪心写写很自豪么。
2015年7月09日 22:32
每天贪心写写很自豪么。
2015年7月09日 22:32
每天贪心写写很自豪么。
2015年7月09日 22:33
每天贪心写写很自豪么。
2015年7月09日 22:33
每天贪心写写很自豪么。
2015年7月09日 22:33
每天贪心写写很自豪么。
2015年7月09日 22:33
每天贪心写写很自豪么。
2015年7月09日 22:34
每天贪心写写很自豪么。
2015年7月09日 22:35
每天贪心写写很自豪么。
2015年7月09日 22:37
每天贪心写写很自豪么。
2015年7月09日 22:37
每天贪心写写很自豪么。
2015年7月09日 22:37
每天贪心写写很自豪么。
2015年7月09日 22:38
每天贪心写写很自豪么。
2015年7月09日 22:38
每天贪心写写很自豪么。
2015年7月09日 22:39
每天贪心写写很自豪么。
2015年7月09日 22:40
每天贪心写写很自豪么。
2015年7月09日 22:40
每天贪心写写很自豪么。
2015年7月09日 22:41
每天贪心写写很自豪么。
2015年7月09日 22:41
每天贪心写写很自豪么。
2015年7月09日 22:42
每天贪心写写很自豪么。
2015年7月15日 09:35
每天贪心写写很自豪么。