【自家測試】2017.12.3
阿新 • • 發佈:2017-12-04
image lib 註意 答案 處理 soft sap b+ char
T1
卡死在T1。
打了兩個小時數位dp,結果tmd是道結論題。
∵d(x)==x%9
∴喜歡的數一定可以寫成(x*9+b)*b==9*x*b+b*b的形式
b從1~9,把d*d按模9的余數分類算一下,然後容斥一下即可。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<vector> #include<queue> #include<stack> using namespace std; #define LL long long LL calc(LL x) { LL res=0,a,b; if(x>=1) res+=(x-1)/9+1; a=x>=4?(x-4)/18+1:0; b=x>=49?(x-49)/63+1:0; res=res+a+b-a/7; a=x>=16?(x-16)/36+1:0LL; b=x>=25?(x-25)/45+1:0; res=res+a+b-a/5; a=x>=9?(x-9)/27+1:0LL; b=x>=36?(x-36)/54+1:0; if(x>=81) res+=x/81; res=res+a+b-a/2; return res; } int main() { int T; LL l,r; scanf("%d",&T); while(T--) { scanf("%lld%lld",&l,&r); printf("%lld\n",calc(r)-calc(l-1)); } return 0; }
忘了return然後wa成傻逼
T2
一個因為數據水可以過的歪解
因為可以發現最小路徑上顯然每個點只會經過一次
只要只要不從從一出去的這條路再走回來即可
枚舉每條出去的邊,刪掉它的反向邊,跑spfa
數據很水,加個slf優化就過了90.第一個點比較毒不管。
//Achen #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<vector> #include<queue> #include<ctime> #include<cmath> const int N=10005; const int M=400007; typedef long long LL; using namespace std; int n,m; template<typename T> void read(T &x) { char ch=getchar(); x=0; T f=1; while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘)) ch=getchar(); if(ch==‘-‘) f=-1,ch=getchar(); for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=x*10+ch-‘0‘; x*=f; } int ecnt=1,fir[N],nxt[M],to[M],val[M]; void add(int u,int v,int w) { nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w; } deque<int>que; int vis[N],dis[N]; int spfa(int idd) { memset(dis,127/3,sizeof(dis)); dis[to[idd]]=0; vis[to[idd]]=1; que.push_back(to[idd]); while(!que.empty()) { int x=que.front(); que.pop_front(); vis[x]=0; for(int i=fir[x];i;i=nxt[i]) if(i!=(idd^1)) { int y=to[i]; if(dis[y]>dis[x]+val[i]) { dis[y]=dis[x]+val[i]; if(!vis[y]) { vis[y]=1; if(!que.empty()) { int tp=que.front(); if(dis[y]<dis[tp]) que.push_front(y); else que.push_back(y); } else que.push_back(y); } } } } return val[idd]+dis[1]; } void work() { int ans=1e9+7; for(int i=fir[1];i;i=nxt[i]) { ans=min(ans,spfa(i)); } printf("%d\n",ans); } void init() { read(n); read(m); for(int i=1;i<=m;i++) { int u,v,w,ww; read(u); read(v); read(w); read(ww); add(u,v,w); add(v,u,ww); } } int main() { #ifdef DEBUG freopen(".in","r",stdin); freopen(".out","w",stdout); #endif init(); work(); return 0; } /* 3 3 1 2 2 1 2 3 4 5 3 1 3 2 */
T3
好像T2,T3搞反了,無所謂了。
二分答案跑有上下界的網絡流。
設現在check的答案為ans
源點向每一行連上界為sumh[i]+ans,下界為max(sumh[i]-ans,0)的邊
每一行向每一列連上界R下界L的邊
每一列向匯點連上界為suml[i]+ans,下界為max(suml[i]-ans,0)的邊
註意超級源點和超級匯點的處理方法,每個點是出流減入流,然後記得匯點向源點連inf的邊
最後判斷超級源點的邊是否滿流即可
又驗證了一下ISAP的優越性
//Achen #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<vector> #include<queue> #include<ctime> #include<cmath> #define inf 0x7fffffff const int N=405; typedef long long LL; using namespace std; int n,m,L,R,tot,lim,a[N][N],b[N][N],sumh[N],suml[N]; template<typename T> void read(T &x) { char ch=getchar(); x=0; T f=1; while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘)) ch=getchar(); if(ch==‘-‘) f=-1,ch=getchar(); for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=x*10+ch-‘0‘; x*=f; } struct edge { int from,to,cap,flow,nxt; edge() {} edge(int from,int to,int cap,int flow,int nxt):from(from),to(to),cap(cap),flow(flow),nxt(nxt) {} }e[N*N*2]; int ecnt=1,fir[N],cur[N]; void add(int u,int v,int w) { e[++ecnt]=edge(u,v,w,0,fir[u]); fir[u]=ecnt; e[++ecnt]=edge(v,u,0,0,fir[v]); fir[v]=ecnt; } int d[N],c[N],p[N],ve[N]; queue<int>que; void bfs(int s,int t) { for(int i=1;i<=tot;i++) d[i]=tot,c[i]=0; d[t]=0; que.push(t); while(!que.empty()) { int x=que.front(); que.pop(); for(int i=fir[x];i;i=e[i].nxt) { int y=e[i].to; if(d[y]==tot&&e[i].flow==e[i].cap) { d[y]=d[x]+1; que.push(y); } } } return; } int cal(int s,int t) { int res=inf; for(int x=t;x!=s;x=e[p[x]].from) res=min(res,e[p[x]].cap-e[p[x]].flow); for(int x=t;x!=s;x=e[p[x]].from) { e[p[x]].flow+=res; e[p[x]^1].flow-=res; } return res; } int ISAP(int s,int t) { bfs(s,t); int res=0; for(int i=1;i<=tot;i++) cur[i]=fir[i],c[d[i]]++; for(int x=s;d[x]<tot;) { if(x==t) { res+=cal(s,t); x=s; } int ok=0; for(int &i=cur[x];i;i=e[i].nxt) { int y=e[i].to; if(d[y]+1==d[x]&&e[i].cap>e[i].flow) { p[x=y]=i; ok=1; break; } } if(!ok) { cur[x]=fir[x]; int M=tot; for(int i=fir[x];i;i=e[i].nxt) { int y=e[i].to; if(e[i].cap>e[i].flow) M=min(M,d[y]+1); } if(M==tot) break; if(!(--c[d[x]])) break; c[d[x]=M]++; if(x!=s) x=e[p[x]].from; } } return res; } void clear() { memset(fir,0,sizeof(fir)); ecnt=1; lim=0; memset(ve,0,sizeof(ve)); } int check(int ans) { clear(); int s=n+m+1,t=s+1,ss=t+1,tt=ss+1; tot=tt; for(int i=1;i<=n;i++) { int up=(ans+sumh[i]),dn=max(0,sumh[i]-ans); add(s,i,up-dn); ve[s]+=dn; ve[i]-=dn; } for(int i=1;i<=m;i++) { int up=(ans+suml[i]),dn=max(0,suml[i]-ans); add(n+i,t,up-dn); ve[n+i]+=dn; ve[t]-=dn; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { int up=R,dn=L; add(i,n+j,up-dn); ve[i]+=dn; ve[n+j]-=dn; } for(int i=1;i<=tot;i++) { if(ve[i]>0) add(i,tt,ve[i]); else if(ve[i]<0) { add(ss,i,-ve[i]); lim-=ve[i];} } add(t,s,inf); return ISAP(ss,tt)>=lim; } void work() { for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) sumh[i]+=a[i][j]; for(int j=1;j<=m;j++) for(int i=1;i<=n;i++) suml[j]+=a[i][j]; int l=0,r=2e5,ans=r; while(l<=r) { int mid=(l+r)>>1; if(check(mid)) ans=mid,r=mid-1; else l=mid+1; } check(ans); printf("%d\n",ans); for(int i=1;i<=n;i++) for(int j=fir[i];j;j=e[j].nxt) if(e[j].to>=n+1&&e[j].to<=n+m) b[i][e[j].to-n]=e[j].flow+L; for(int i=1;i<=n;i++) { for(int j=1;j<m;j++) printf("%d ",b[i][j]); printf("%d",b[i][m]); printf("\n"); } } void init() { read(n); read(m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(a[i][j]); read(L); read(R); } int main() { #ifdef DEBUG freopen(".in","r",stdin); freopen(".out","w",stdout); #endif init(); work(); return 0; } /* 2 2 0 1 2 1 0 1 */
【自家測試】2017.12.3