2015-2016 Northwestern European Regional Contest (NWERC 2015)
Problem A
直接用优先队列进行贪心即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<cmath> 7 #include<string> 8 #include<set> 9 #include<queue> 10 #include<map> 11 using namespace std; 12 const int inf=(1<<30)-1; 13 const int maxn=300010; 14 #define REP(i,n) for(int i=(0);i<(n);i++) 15 #define FOR(i,j,n) for(int i=(j);i<=(n);i++) 16 #define Rep(x) for(int i=head[x],y;~i;i=e[i].next) if(!vis[y=e[i].to]) 17 typedef long long ll; 18 typedef pair<int,int> PII; 19 int IN(){ 20 int c,f,x; 21 while (!isdigit(c=getchar())&&c!='-');c=='-'?(f=1,x=0):(f=0,x=c-'0'); 22 while (isdigit(c=getchar())) x=(x<<1)+(x<<3)+c-'0';return !f?x:-x; 23 } 24 #define de(x) cout << #x << "=" << x << endl 25 #define MP make_pair 26 #define PB push_back 27 #define fi first 28 #define se second 29 int n,m,T; 30 struct data{ 31 int l,r; 32 }a[maxn]; 33 bool cmp(data a,data b) 34 { 35 return a.l<b.l; 36 } 37 priority_queue<int,vector<int>,greater<int> > Q; 38 int main() 39 { 40 while(~scanf("%d%d",&n,&m)) 41 { 42 FOR(i,1,n) { 43 a[i].l=IN(); 44 a[i].r=IN(); 45 a[i].r+=a[i].l; 46 } 47 sort(a+1,a+n+1,cmp); 48 Q.push(a[1].r+m); 49 int ans=0; 50 for(int i=2;i<=n;i++) 51 { 52 while(!Q.empty()&&Q.top()<a[i].l) Q.pop(); 53 int u=Q.top(); 54 if(u-m<=a[i].l&&a[i].l<=u) ans++,Q.pop(); 55 Q.push(a[i].r+m); 56 } 57 printf("%d\n",ans); 58 while(!Q.empty()) Q.pop(); 59 } 60 return 0; 61 }
Problem B
比赛时居然现场没人开这道题
其实就是一个简单的dp
先要把所有包含的全部删除
f[i][j]代表前i个人分成j组的最大值
f[i][j] = max(f[i][j], f[k- 1][j - 1] + h[k].b - h[k].a)
排序后枚举k进行简单的转移即可
最后统计一下答案
——hnqw1214
……其实也不简单
这道题关键就是要想到把些时间段包含别人的人全部扔出来,放到另外一个地方。
去重蛮难想的,QW写的。
最后还要和之前的状态混合枚举一下。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 #define dec(i, a, b) for (int i(a); i >= (b); --i) 7 #define fi first 8 #define se second 9 10 struct ss 11 { 12 int a,b; 13 }; 14 ss g[210], h[210]; 15 ss d[210]; 16 int n,p; 17 bool contain(ss a,ss b){ 18 return a.a<=b.a&&a.b>=b.b; 19 } 20 21 bool b[1010]; 22 23 int f[203][203]; 24 int ans = 0; 25 int et = 0; 26 27 bool cmp(const ss &a, const ss &b){ 28 return a.b - a.a > b.b - b.a; 29 } 30 31 bool cmp1(const ss &a, const ss &b){ 32 return a.a < b.a; 33 } 34 35 int main() 36 { 37 38 scanf("%d%d",&n,&p); 39 int i,j; 40 for (i=1;i<=n;i++) 41 scanf("%d%d",&g[i].a,&g[i].b); 42 int cnt=0; 43 for (i=1;i<n;i++) 44 for (j=i+1;j<=n;j++) 45 { 46 if (contain(g[i],g[j])) 47 b[i]=true; 48 else if (contain(g[j],g[i])) 49 b[j]=true; 50 } 51 52 53 for (i=1;i<=n;i++) if (!b[i]) h[++cnt]=g[i]; 54 55 sort(h + 1, h + cnt + 1, cmp1); 56 57 58 // printf("%d\n", cnt); 59 // rep(i, 1, cnt) printf("%d %d\n", h[i].a, h[i].b); 60 61 rep(i, 1, n) if (b[i]) d[++et] = g[i]; 62 63 sort(d + 1, d + et + 1, cmp); 64 65 rep(i, 0, cnt) rep(j, 0, p) f[i][j] = -(1e9 + 10000); 66 f[0][0] = 0; 67 rep(k, 1, p){ 68 rep(i, 1, cnt){ 69 rep(j, 1, i){ 70 if (h[j].b - h[i].a <= 0) continue; 71 f[i][k] = max(f[i][k], f[j - 1][k - 1] + h[j].b - h[i].a); 72 } 73 } 74 } 75 76 77 // ans = f[cnt][p]; 78 int ff = 0; 79 rep(i, 0, p){ 80 ff = ff + d[i].b - d[i].a; 81 if (p >= i) ans = max(ans, ff + f[cnt][p - i]); 82 } 83 84 printf("%d\n", ans); 85 86 87 88 }
Problem C
首先预处理一下哪些线段是相交的
然后把每条线段看成一个点
如果线段相交就连一条边
判断一下这张图是否是二分图
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cstring> 7 #include<string> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #include<queue> 12 13 using namespace std; 14 15 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 16 #define dec(i, a, b) for (int i(a); i >= (b); --i) 17 #define fi first 18 #define se second 19 20 typedef long long LL; 21 22 const double eps = 1e-8; 23 24 double sgn(double x){ 25 if (fabs(x) < eps)return 0; 26 if(x < 0)return -1; 27 else return 1; 28 } 29 30 struct point 31 { 32 double x,y; 33 point(){} 34 point(double _x,double _y):x(_x),y(_y) 35 {} 36 point operator -(const point &b) const 37 { 38 return point(x-b.x,y-b.y); 39 } 40 double operator *(const point &b) const 41 { 42 return x*b.x+y*b.y; 43 } 44 double operator ^(const point &b) const 45 { 46 return x*b.y-y*b.x; 47 } 48 }; 49 struct line 50 { 51 point s,e; 52 double a,b,c; 53 line() 54 { 55 56 } 57 line (point _s,point _e):s(_s),e(_e) 58 { 59 a=e.y-s.y; 60 b=s.x-e.x; 61 c=e.x*s.y-s.x*e.y; 62 } 63 }; 64 double cross(point sp,point ep,point op) 65 { 66 return (sp.x-op.x)*(ep.y-op.y)-(sp.y-op.y)*(ep.x-op.x); 67 } 68 bool samepoint(point p1,point p2) 69 { 70 if (fabs(p1.x-p2.x)>eps) return false; 71 if (fabs(p1.y-p2.y)>eps) return false; 72 return true; 73 } 74 bool inter(line l1,line l2) 75 { 76 return 77 max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) && 78 max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) && 79 max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) && 80 max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) && 81 sgn((l2.s-l1.s)^(l1.e-l1.s))*sgn((l2.e-l1.s)^(l1.e-l1.s)) <= 0 && 82 sgn((l1.s-l2.s)^(l2.e-l2.s))*sgn((l1.e-l2.s)^(l2.e-l2.s)) <= 0; 83 } 84 point intersection(line u,line v) 85 { 86 point p; 87 p.x=(cross(v.e,u.e,u.s)*v.s.x-cross(v.s,u.e,u.s)*v.e.x)/(cross(v.e,u.e,u.s)-cross(v.s,u.e,u.s)); 88 p.y=(cross(v.e,u.e,u.s)*v.s.y-cross(v.s,u.e,u.s)*v.e.y)/(cross(v.e,u.e,u.s)-cross(v.s,u.e,u.s)); 89 return p; 90 } 91 point interpoint(line l1, line l2) 92 { 93 point tmp; 94 if(fabs(l1.b)<eps) 95 { 96 tmp.x=-l1.c/l1.a; 97 tmp.y=(-l2.c-l2.a*tmp.x)/l2.b; 98 } 99 else 100 { 101 tmp.x=(l1.c*l2.b-l1.b*l2.c)/(l1.b*l2.a-l2.b*l1.a); 102 tmp.y=(-l1.c-l1.a*tmp.x)/l1.b; 103 } 104 return tmp; 105 } 106 int w,p,cnt; 107 point well[1010]; 108 line pipe[1010]; 109 int f[1010][1010]; 110 pair<int,int> g[1000010]; 111 int can[1010]; 112 int used[1010]; 113 114 vector <int> e[1010]; 115 vector <int> v[1010]; 116 117 118 119 void dfs(int x, int now){ 120 // printf("%d %d\n", x, now); 121 if (now == cnt){ 122 puts("possible"); 123 exit(0); 124 } 125 126 if (x > p) return ; 127 128 dfs(x + 1, now); 129 130 131 132 if (can[x] == 0){ 133 for (auto u : e[x]){ 134 can[u] = 1; 135 } 136 137 vector <int> ct; 138 139 for (auto u : v[x]){ 140 if (!used[u]){ 141 ct.push_back(u); 142 used[u] = 1; 143 } 144 } 145 146 dfs(x + 1, now + (int)ct.size()); 147 148 for (auto u : ct) used[u] = 0; 149 } 150 } 151 int vis[100010]; 152 int main(){ 153 154 155 156 scanf("%d%d",&w,&p); 157 158 int i,j; 159 for (i=1;i<=w;i++) 160 scanf("%lf%lf",&well[i].x,&well[i].y); 161 for (i=1;i<=p;i++) 162 { 163 point po; 164 int id; 165 scanf("%d%lf%lf",&id,&po.x,&po.y); 166 pipe[i]=line(well[id],po); 167 } 168 // printf("%d %d\n", w, p); 169 cnt=0; 170 for (i=1;i<p;i++){ 171 for (j=i+1;j<=p;j++){ 172 if (inter(pipe[i],pipe[j])&&!samepoint(pipe[i].s,interpoint(pipe[i],pipe[j]))||samepoint(pipe[i].e,pipe[j].e)){ 173 cnt++; 174 f[i][j]=cnt; 175 g[cnt].first=i; 176 g[cnt].second=j; 177 } 178 } 179 } 180 /* 181 rep(i, 1, p){ 182 rep(j, 1, p) printf("%d ", f[i][j]); 183 putchar(10); 184 } 185 */ 186 rep(i, 1, p) rep(j, 1, p) if (i > j) f[i][j] = f[j][i]; 187 188 rep(i, 1, p){ 189 rep(j, 1, p) if (f[i][j] > 0) v[i].push_back(f[i][j]), e[i].push_back(j); 190 } 191 /* 192 rep(i, 1, p){ 193 for (auto u : v[i]) printf("%d ", u); 194 putchar(10); 195 } 196 */ 197 //dfs(1, 0); 198 queue<int> Q; 199 rep(i,1,p) { 200 if(vis[i]) continue; 201 Q.push(i);vis[i]=1; 202 while(!Q.empty()) { 203 int u=Q.front();Q.pop(); 204 for(auto x:e[u]) { 205 if(vis[x]==vis[u]) return puts("impossible"),0; 206 else if(!vis[x]) vis[x]=(vis[u]==1)?2:1,Q.push(x); 207 } 208 } 209 } 210 puts("possible"); 211 212 return 0; 213 214 }
Problem D
根据题意进行记忆化搜索
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 #define dec(i, a, b) for (int i(a); i >= (b); --i) 7 8 typedef long long LL; 9 10 const int N = 1e6 + 10; 11 12 LL n, r, p; 13 LL f[N]; 14 15 LL dp(LL n){ 16 if (n <= 1) return 0; 17 if (~f[n]) return f[n]; 18 LL ret = 6e18; 19 for (LL i = 2;i <= n; i++) ret = min(ret, dp((n - 1) / i + 1) + (i - 1) * p + r); 20 return f[n] = ret; 21 } 22 23 int main(){ 24 25 scanf("%lld%lld%lld", &n, &r, &p); 26 memset(f, -1, sizeof f); 27 printf("%lld\n", dp(n)); 28 return 0; 29 }
Problem E
构造二分图
把所有的算式看成一个点集
所有的答案看成一个点集
如果算式可以得到该答案就连边
然后求二分图的最大匹配
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 struct ss 5 { 6 ll x,y; 7 } a[2510]; 8 unordered_map<ll,ll> mat,used; 9 ll result[2521],fuhao[2521],n; 10 bool crosspath(int k) 11 { 12 ll j=a[k].x+a[k].y; 13 if (!used[j]) 14 { 15 used[j]=1; 16 if (mat[j]==0||crosspath(mat[j])) 17 { 18 mat[j]=k; 19 result[k]=j; 20 fuhao[k]=0; 21 return true; 22 } 23 } 24 j=a[k].x-a[k].y; 25 if (!used[j]) 26 { 27 used[j]=1; 28 if (mat[j]==0||crosspath(mat[j])) 29 { 30 mat[j]=k; 31 result[k]=j; 32 fuhao[k]=1; 33 return true; 34 } 35 } 36 j=a[k].x*a[k].y; 37 if (!used[j]) 38 { 39 used[j]=1; 40 if (mat[j]==0||crosspath(mat[j])) 41 { 42 mat[j]=k; 43 result[k]=j; 44 fuhao[k]=2; 45 return true; 46 } 47 } 48 return false; 49 } 50 int main() 51 { 52 scanf("%lld",&n); 53 int i; 54 for (i=1;i<=n;i++) 55 scanf("%lld%lld",&a[i].x,&a[i].y); 56 int match=0; 57 for (i=1;i<=n;i++) 58 { 59 if (crosspath(i)) 60 match++; 61 used.clear(); 62 } 63 if (match<n) 64 puts("impossible"); 65 else 66 { 67 for (i=1;i<=n;i++) 68 { 69 printf("%lld ",a[i].x); 70 if (fuhao[i]==0) printf("+ "); 71 else if (fuhao[i]==1) printf("- "); 72 else printf("* "); 73 printf("%lld ",a[i].y); 74 printf("= "); 75 printf("%lld\n",result[i]); 76 } 77 } 78 return 0; 79 }
Problem F
Problem G
其实就是一个三维偏序问题
用cdq分治求解即可
(模板题哦)
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 #define dec(i, a, b) for (int i(a); i >= (b); --i) 7 8 typedef long long LL; 9 10 const int N = 1e6 + 10; 11 12 struct Node 13 { 14 int x, y, z, f, cnt; 15 void read() { f = 0; } 16 bool operator < (const Node &rhs) const 17 { 18 if (x != rhs.x) return x < rhs.x; 19 if (y != rhs.y) return y < rhs.y; 20 return z < rhs.z; 21 } 22 bool operator == (const Node &rhs) const 23 { return x == rhs.x && y == rhs.y && z == rhs.z; } 24 } 25 26 a[N], b[N]; 27 28 29 int n, st[N<<1], ans[N]; 30 31 void init(){ 32 sort(a + 1, a + n + 1); 33 int sz = 0; 34 for (int i = 1; i <= n; ++i) 35 { 36 b[++sz] = a[i]; b[sz].cnt = 1; int j = i; 37 while (j < n && a[j + 1] == a[j]) { ++j; b[sz].cnt++;} 38 i = j; 39 } 40 n = sz; 41 memset(st, 0, sizeof st); 42 } 43 44 void add(int k, int num){ 45 while (k <= n) 46 { 47 st[k] += num; 48 k += k & (-k); 49 } 50 } 51 int query(int k){ 52 int ans = 0; 53 while (k){ 54 ans += st[k]; 55 k -= k & (-k); 56 } 57 return ans; 58 } 59 60 void cdq(int l, int r){ 61 if (l == r) return; 62 int mid = l + r >> 1; 63 cdq(l, mid); 64 cdq(mid + 1, r); 65 int i = l, j = mid + 1; 66 for (int p = l; p <= r; ++p) 67 { 68 if (i <= mid && (j > r || b[i].y <= b[j].y)) 69 { 70 add(b[i].z, b[i].cnt); 71 a[p] = b[i++]; 72 } else { 73 b[j].f += query(b[j].z); 74 a[p] = b[j++]; 75 } 76 } 77 for (int i = l; i <= mid; ++i) 78 add(b[i].z, -b[i].cnt); 79 for (int i = l; i <= r; ++i) 80 b[i] = a[i]; 81 } 82 83 int main(){ 84 85 scanf("%d", &n); 86 rep(i, 1, n){ 87 int x; 88 scanf("%d", &x); 89 a[x].x = i; 90 } 91 92 rep(i, 1, n){ 93 int x; 94 scanf("%d", &x); 95 a[x].y = i; 96 } 97 98 rep(i, 1, n){ 99 int x; 100 scanf("%d", &x); 101 a[x].z = i; 102 } 103 104 // rep(i, 1, n) printf("%d %d %d\n", a[i].x, a[i].y, a[i].z); 105 106 107 int sav = n; 108 init(); 109 cdq(1, n); 110 LL ret = 0; 111 for (int i = 1; i <= n; ++i) ret += (LL)b[i].f; 112 printf("%lld\n", ret); 113 return 0; 114 }
Problem H
Problem I
根据题意进行模拟
不断地更新x,y的值即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cstring> 7 #include<string> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #include<queue> 12 using namespace std; 13 char s[35]; 14 int main() 15 { 16 scanf("%s",s); 17 int level=strlen(s); 18 int i; 19 int x=0,y=0; 20 for (i=0;i<level;i++) 21 { 22 int num=s[i]-'0'; 23 x<<=1; 24 y<<=1; 25 if (num==1) x++; 26 else if (num==2) y++; 27 else if (num==3) 28 { 29 x++; 30 y++; 31 } 32 //cout<<x<<" "<<y<<endl; 33 } 34 printf("%d %d %d\n",level,x,y); 35 return 0; 36 }
Problem J
直接可以预处理出所有答案
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<cmath> 7 #include<string> 8 #include<set> 9 #include<queue> 10 #include<map> 11 using namespace std; 12 const int inf=(1<<30)-1; 13 const int maxn=100010; 14 #define REP(i,n) for(int i=(0);i<(n);i++) 15 #define FOR(i,j,n) for(int i=(j);i<=(n);i++) 16 #define Rep(x) for(int i=head[x],y;~i;i=e[i].next) if(!vis[y=e[i].to]) 17 typedef long long ll; 18 typedef pair<int,int> PII; 19 int IN(){ 20 int c,f,x; 21 while (!isdigit(c=getchar())&&c!='-');c=='-'?(f=1,x=0):(f=0,x=c-'0'); 22 while (isdigit(c=getchar())) x=(x<<1)+(x<<3)+c-'0';return !f?x:-x; 23 } 24 #define de(x) cout << #x << "=" << x << endl 25 #define MP make_pair 26 #define PB push_back 27 #define fi first 28 #define se second 29 int n,T; 30 int a[260],ans[260]; 31 int main() 32 { 33 for(int i=0;i<256;i++) 34 a[i]=(i^(i<<1))%256,ans[a[i]]=i; 35 while(~scanf("%d",&n)) 36 { 37 int x; 38 for(int i=1;i<=n;i++) 39 { 40 x=IN(); 41 printf("%d%c",ans[x],i==n?'\n':' '); 42 } 43 } 44 return 0; 45 }
Problem K
题目看似比较复杂
其实是一个简单的计数原理
因为每顿餐都最多只有25种
所以可以直接枚举每种搭配
求出每种搭配要用到的佐料
用乘法原理进行统计
为防止溢出,在进行乘法计算时可以用除法先判断一下是否越界
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cstring> 7 #include<string> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #include<queue> 12 using namespace std; 13 typedef long long ll; 14 ll r,s,m,d,n; 15 ll b[1010]; 16 ll sum[1010][21]; 17 bool can[1010][1010]; 18 ll ans; 19 set<ll> se; 20 void calc(int x,int y,int z) 21 { 22 int i; 23 se.clear(); 24 for (i=1;i<=sum[x][0];i++) 25 se.insert(sum[x][i]); 26 for (i=1;i<=sum[y][0];i++) 27 se.insert(sum[y][i]); 28 for (i=1;i<=sum[z][0];i++) 29 se.insert(sum[z][i]); 30 ll sum=1; 31 for (auto u:se) 32 { 33 if (1e18 / sum < b[u]) 34 { 35 puts("too many"); 36 exit(0); 37 } 38 sum=sum*b[u]; 39 if (sum>1e18) 40 { 41 puts("too many"); 42 exit(0); 43 } 44 } 45 ans=ans+sum; 46 if (ans>1e18) 47 { 48 puts("too many"); 49 exit(0); 50 } 51 } 52 int main() 53 { 54 scanf("%lld%lld%lld%lld%lld",&r,&s,&m,&d,&n); 55 int i,j,k; 56 for (i=1;i<=r;i++) 57 scanf("%lld",&b[i]); 58 for (i=1;i<=s+m+d;i++) 59 { 60 scanf("%lld",&sum[i][0]); 61 for (j=1;j<=sum[i][0];j++) 62 scanf("%lld",&sum[i][j]); 63 } 64 memset(can,true,sizeof(can)); 65 for (i=1;i<=n;i++) 66 { 67 ll x,y; 68 scanf("%lld%lld",&x,&y); 69 can[x][y]=false; 70 can[y][x]=false; 71 } 72 ans=0; 73 for (i=1;i<=s;i++) 74 for (j=s+1;j<=s+m;j++) 75 for (k=s+m+1;k<=s+m+d;k++) 76 if (can[i][j]&&can[i][k]&&can[j][k]) 77 calc(i,j,k); 78 printf("%lld\n",ans); 79 }