第二周周练
字符串hash进行比较。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; const LL mod=1e9+7; string s1,s2; LL p[100005]; int main(){ p[0]=1; for(int i=1;i<100003;i++){ p[i]=(p[i-1]*26)%mod; } int t; cin>>t; while(t--){ cin>>s1>>s2; int ans=0; LL sum1=0,sum2=0; int len1=s1.size(); int len2=s2.size(); int len=min(len1,len2); for(int i=0;i<len;i++){ LL v2=i,v1=len1-i-1; sum1=( sum1+(LL)(s1[v1]-'a')*p[i] )%mod; sum2=( sum2*26+(LL)(s2[v2]-'a') )%mod; if(sum1==sum2) ans++; } cout<<ans<<endl; } return 0; }
贪心。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> using namespace std; double a[4005]; int n; int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=1;i<=2*n;i++) scanf("%lf",&a[i]); int cnt=0; double sum=0; for(int i=1;i<=2*n;i++){ if(a[i]-(int)a[i]<0.000001) cnt++; else sum+=a[i]-(int)a[i]; } sum-=max(0,n-cnt); cnt=min(n,cnt); double ans=fabs(sum); for(int i=1;i<=cnt;i++){ ans=min(ans,fabs(sum-i)); } printf("%.3lf\n",ans); } return 0; }
偶数考虑 i-1 和 i/2,奇数考虑 i-1 和 (i+1)/2。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <queue> #include <map> using namespace std; typedef long long LL; LL ans[10000006]; int n,x,y; int main(){ while(cin>>n>>x>>y){ ans[1]=x; for(int i=2;i<=n;i++){ if(i%2==0) ans[i]=min(ans[i-1]+x,ans[i/2]+y); else ans[i]=min(ans[i-1]+x,ans[i/2+1]+x+y); } cout<<ans[n]<<endl; } return 0; }
网络流。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #define inf 0x3f3f3f3f using namespace std; typedef pair<int,int> P; struct edge{ int to,cap,cost,rev; }; vector<edge> g[1000005]; int V,n,m; int dis[1000005],vis[1000005]; int prevv[1000005],preve[1000005]; void addedge(int from,int to,int cap,int cost){ g[from].push_back((edge){to,cap,cost,g[to].size()}); g[to].push_back((edge){from,0,-cost,g[from].size()-1}); } void SPFA(int s,int t){ fill(dis,dis+V,inf); fill(vis,vis+V,0); dis[s]=0; vis[s]=1; queue<int> q; q.push(s); while(!q.empty()){ int v=q.front(); q.pop(); vis[v]=0; for(int i=0;i<g[v].size();i++){ edge &e=g[v][i]; if(e.cap>0&&dis[e.to]>dis[v]+e.cost){ dis[e.to]=dis[v]+e.cost; prevv[e.to]=v; preve[e.to]=i; vis[e.to]=1; q.push(e.to); } } } } int min_cost_flow(int s,int t,int f){ int res=0; while(f>0){ SPFA(s,t); if(dis[t]==inf) return -1; int d=f; for(int v=t;v!=s;v=prevv[v]){ d=min(d,g[prevv[v]][preve[v]].cap); } f-=d; res+=d*dis[t]; for(int v=t;v!=s;v=prevv[v]){ edge &e=g[prevv[v]][preve[v]]; e.cap-=d; g[v][e.rev].cap+=d; } } return res; } int a[1005],b[1005]; int p,q; void solve(int u){ vector<int> v; for(int i=0;i<g[u].size();i++){ if(g[u][i].cap) v.push_back(g[u][i].to); } sort(v.begin(),v.end()); for(int i=0;i<v.size();i++){ printf("%d",v[i]); if(i==v.size()-1) printf("\n"); else printf(" "); } } int main(){ while(~scanf("%d%d%d",&n,&p,&q)){ V=n+4; for(int i=0;i<V;i++) g[i].clear(); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&b[i]); for(int i=1;i<=n;i++){ addedge(0,i,1,0); addedge(i,n+1,1,-a[i]); addedge(i,n+2,1,-b[i]); } addedge(n+1,n+3,p,0); addedge(n+2,n+3,q,0); int ans=-min_cost_flow(0,n+3,p+q); printf("%d\n",ans); solve(n+1); solve(n+2); } return 0; }
先把边排序,按顺序用并查集合并,注意两边的大小是否大于t。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int N=250005; struct node{ int from,to,val; } g[4*N]; bool cmp(node x,node y){ return x.val<y.val; } int cnt; int f[N]; int sz[N]; int ans[N]; int n,m,t,V; void addedge(int u,int v,int val){ g[cnt++]=(node){u,v,val}; } void init(){ V=n*m; cnt=0; for(int i=1;i<=V;i++){ f[i]=i; sz[i]=1; ans[i]=0; } } int getid(int x,int y){ return (x-1)*m+y; } int find(int x){ return f[x]==x?x:f[x]=find(f[x]); } void merge(int x,int y,int val){ int fx=find(x); int fy=find(y); if(fx==fy) return; if(sz[fx]<sz[fy]) swap(fx,fy); if(sz[fx]<t&&sz[fy]<t){ ans[fy]=val; sz[fy]+=sz[fx]; f[fx]=fy; } if(sz[fx]>=t&&sz[fy]<t){ ans[fy]=val; sz[fy]=t; } } int a[505][505]; int fx[]={1,0}; int fy[]={0,1}; int main(){ while(~scanf("%d%d%d",&n,&m,&t)){ init(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%d",&a[i][j]); } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ for(int k=0;k<2;k++){ int xx=i+fx[k]; int yy=j+fy[k]; if(xx>n||yy>m) continue; addedge(getid(i,j),getid(xx,yy), abs(a[xx][yy]-a[i][j])); } } sort(g,g+cnt,cmp); for(int i=0;i<cnt;i++){ if(find(g[i].from)==find(g[i].to)) continue; merge(g[i].from,g[i].to,g[i].val); } long long sum=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ int xx; cin>>xx; if(xx==1) sum+=ans[find(getid(i,j))]; } cout<<sum<<endl; } return 0; }
素数筛,并查集合并有相同素因子的元素
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> using namespace std; typedef long long LL; int f[1000010]; int find(int x){ return f[x]==x?x:f[x]=find(f[x]); } void merge(int x,int y){ int fx=find(x); int fy=find(y); f[fx]=fy; } vector<int> p; int vis[1000010]; void init(){ for(int i=2;i<=1000006;i++){ if(!vis[i]){ p.push_back(i); LL k=(LL)i*i; while(k<=1000006){ vis[k]=1; k+=i; } } } } int n; void solve(int x){ vector<int> g; for(int i=0;p[i]*p[i]<=x;i++){ if(x%p[i]==0){ g.push_back(p[i]); vis[p[i]]=1; while(x%p[i]==0) x/=p[i]; } } if(x>1) g.push_back(x),vis[x]=1;; for(int i=1;i<g.size();i++){ merge(g[0],g[i]); } } int k[1000010]; int main(){ init(); int t; scanf("%d",&t); int T=t; while(t--){ memset(vis,0,sizeof(vis)); memset(k,0,sizeof(k)); for(int i=1;i<=1000006;i++) f[i]=i; int ans=0; scanf("%d",&n); for(int i=1;i<=n;i++){ int a; scanf("%d",&a); if(a==1){ ans++; continue; } solve(a); } for(int i=0;i<p.size();i++){ if(vis[p[i]]){ if(!k[find(p[i])]){ k[find(p[i])]=1; ans++; } } } printf("Case %d: %d\n",T-t,ans); } return 0; }