17-10-18模拟赛

T1:

固定一个方向的刀数的时候,平均切时答案最大。
可以发现,如果能够只切一边,只切一边一定最优。
当n<=m,k>=m时,考虑将一边全部切开,剩下的平均切到另一边。
因为n/(k-(n-1))>=m/(k-(m-1)),所以长边切m-1刀,短边切k-(m-1)刀一定最优。

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define ll long long
 5 using namespace std;
 6 inline ll in(){
 7     ll x=0;bool f=0; char c;
 8     for (;(c=getchar())<'0'||c>'9';f=c=='-');
 9     for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0');
10     return f?-x:x;
11 }
12 ll n,m,k;
13 int main()
14 {
15     n=in();m=in();k=in();
16     if (n<m) swap(n,m);
17     if (k>n+m-2) {printf("-1");return 0;}
18     if (k<m) printf("%lld",max((m/(k+1))*n,(n/(k+1))*m));
19     else if (k<n) printf("%lld",max(n/(k-m+2),(n/(k+1))*m));
20     else printf("%lld",max(n/(k-m+2),m/(k-n+2)));return 0;
21 }

T2:注意到ai不超过30,所以选择的bi小于59,否则选择1一定不劣。

注意到58以内只有16个质数,考虑将选择这些质数的状态压缩后dp即可,时间复杂度O(2^16*n*58).

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define inf 0x3f3f3f3f
 5 #define MN 102
 6 #define Range 59
 7 #define Rp 16
 8 using namespace std;
 9 inline int in(){
10     int x=0;bool f=0; char c;
11     for (;(c=getchar())<'0'||c>'9';f=c=='-');
12     for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0');
13     return f?-x:x;
14 }
15 const int pri[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
16 int f[MN][(1<<Rp)],pre[MN][(1<<Rp)],a[MN],s[Range],st[MN];
17 int n,mn=inf,p=0;
18 int main()
19 {
20     n=in();for (int i=1;i<=n;++i) a[i]=in();
21     memset(f,0x3f,sizeof(f));f[0][0]=0;
22     for (int i=1;i<Range;++i)
23     for (int j=0;j<Rp;++j) if (!(i%pri[j])) s[i]|=(1<<j);
24     for (int i=1;i<=n;++i)
25     for (int j=0;j<(1<<Rp);++j)
26     for (int k=1;k<Range;++k)
27     if (!(j&s[k])&&f[i][j|s[k]]>f[i-1][j]+abs(a[i]-k)) 
28     f[i][j|s[k]]=f[i-1][j]+abs(a[i]-k),pre[i][j|s[k]]=k;
29     for (int i=0;i<(1<<Rp);++i) if (f[n][i]<mn) mn=f[n][i],p=i;
30     for (int i=n;i;p^=s[pre[i][p]],--i) st[i]=pre[i][p];
31     for (int i=1;i<=n;++i) printf("%d ",st[i]);return 0;
32 }

T3:对新加边去重,对于每个点的边只保留边权最小的边,然后做最短路。

一条新加边如果长度不是到该点最短路的长度一定可以去掉,否则只有满足有其它最短路径到达这个点的时候才可以去掉。

因此算出到每个点最短路条数是否大等于2即可。

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<queue>
 5 #define mp(x,y) make_pair(x,y)
 6 #define ll long long
 7 #define inf 0x3f3f3f3f
 8 #define ME 500005
 9 #define MN 50005
10 using namespace std;
11 inline int in(){
12     int x=0;bool f=0; char c;
13     for (;(c=getchar())<'0'||c>'9';f=c=='-');
14     for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0');
15     return f?-x:x;
16 }
17 struct edge{
18     int to,next;
19     ll val;
20 }e[ME];
21 int head[MN],num[MN],n,m,k,s,u,v,cnt=0,res;
22 ll dis[MN],dst[MN],t,w;
23 inline void ins(int x,int y,ll v){
24     e[++cnt].to=y;e[cnt].next=head[x];head[x]=cnt;e[cnt].val=v;
25 }
26 typedef pair<ll,int> pr;
27 inline void dij(int s){
28     priority_queue<pr,vector<pr>,greater<pr> > q;
29     memset(dis,0x3f,sizeof(dis));
30     dis[s]=0ll;q.push(mp(0ll,s));
31     while (!q.empty()){
32         pr x=q.top();int u=x.second;q.pop();
33         if (dis[u]<x.first) continue;
34         for (int i=head[u];i;i=e[i].next){
35             int v=e[i].to;
36             if (dis[v]>dis[u]+e[i].val){
37                 dis[v]=dis[u]+e[i].val;
38                 q.push(mp(dis[v],v));num[v]=num[u];
39             }else if (dis[v]==dis[u]+e[i].val) num[v]=min(num[u]+num[v],inf);
40         }
41     }
42 }
43 int main()
44 {
45     n=in();m=in();k=in();
46     for (int i=1;i<=m;++i){
47         u=in();v=in();scanf("%lld",&t);
48         ins(u,v,t);ins(v,u,t);
49     }for (int i=1;i<=k;++i){
50         s=in();scanf("%lld",&w);
51         if (dst[s]) ++res,dst[s]=min(dst[s],w);
52         else dst[s]=w;
53     }for (int i=2;i<=n;++i)
54     if (dst[i]) ins(1,i,dst[i]),ins(i,1,dst[i]);dij(1);
55     for (int i=2;i<=n;++i){
56         if (dst[i]&&(dis[i]<dst[i]||(dis[i]==dst[i]&&num[i]>1))) ++res;
57     }printf("%d",res);return 0;
58 }

 

posted on 2017-10-19 17:17  whz2002  阅读(132)  评论(0编辑  收藏  举报