NWERC 2015 模拟赛 Gym 101485
感觉西北欧的题有点简单啊
Jumbled Communication
水题,暴力处理0到255所有数,在暴力查询即可,注意边界溢出之类的。
#include<bits/stdc++.h>
#include<stdlib.h>
#define M(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MAXN=100007;
const int oo=0x3f3f3f3f;
typedef long long LL;
unsigned char has[300];
int num[MAXN];
int main()
{
for(unsigned char i=0;;i++)
{
has[i]=i^(i<<1);
if(i==255) break;
}
int n;
while(scanf("%d",&n)==1)
{
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
for(int i=1;i<=n;i++)
{
unsigned char c=num[i];
for(int j=0;j<=255;j++)
{
if(has[j]==c)
{
printf("%d%c",j,i==n?'\n':' ');
break;
}
}
}
}
return 0;
}
Identifying Map Tiles
简单题,按题意处理就好,可能需要想一下。
#include<bits/stdc++.h>
#include<stdlib.h>
#define M(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MAXN=100007;
const int oo=0x3f3f3f3f;
typedef long long LL;
LL pp[32];
int main()
{
string s;
while(cin>>s)
{
pp[0]=1;
for(int i=1;i<=31;i++)
{
pp[i]=pp[i-1]*2;
}
int n=s.length();
LL x=0,y=0;
for(int i=0;i<n;i++)
{
if(s[i]=='0')
{
}
else if(s[i]=='1')
x+=pp[n-i-1];
else if(s[i]=='2')
y+=pp[n-i-1];
else if(s[i]=='3')
{
x+=pp[n-i-1];
y+=pp[n-i-1];
}
}
printf("%d %lld %lld\n",n,x,y);
}
return 0;
}
Elementary Math
给一些两个数字的数学式,让你在中间添加号或减号或乘号,使得每个式子的结果都不一样。
是一个二分图匹配模型。左边点是每个式子,右边是所有可能的结果。每个式子向他的三种结果连边,跑匈牙利。如果结果等于式子数,那么可以,暴力查询输出方案即可。注意map存了每个结果,还要存结果的反映射,这样在查询方案时就方便了。
#include<bits/stdc++.h>
#include<stdlib.h>
#define M(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MAXN=10007;
const int oo=0x3f3f3f3f;
typedef long long LL;
struct BPM
{
int n, m;
vector<int > G[MAXN];
int left[MAXN];
int right[MAXN];
bool T[MAXN];
bool S[MAXN];
void init(int n, int m)
{
this->n=n;
this->m=m;
for(int i=1; i<=n; i++) G[i].clear();
}
void addEdge(int u, int v)
{
G[u].push_back(v); //建边
}
bool match(int u)
{
S[u]=true; //标记右边的点u
for(int i=0; i<G[u].size(); i++) //遍历由u点出发,连接的左边的点
{
int v=G[u][i];
if(!T[v]) //左边的没标记过的点, 走没匹配过的边
{
T[v]=true;
if(left[v]==-1||match(left[v])) //走匹配过的边到右边的点
{
left[v]=u;
right[u]=v;
return true;
}
}
}
return false;
}
int solve()
{
memset(left, -1, sizeof(left));
memset(right, -1, sizeof(right));
int ans=0;
for(int u=1; u<=n; u++)
{
memset(S, 0, sizeof(S));
memset(T, 0, sizeof(T));
if(match(u)) ans++; //先用匈牙利算法求出最大匹配
}
return ans;
}
} bpm;
map<LL, int>mp;
LL has[MAXN];
struct DS
{
LL a, b;
LL res;
int fh;//1+ 2- 3*
}ds[2505];
int main()
{
int n;
while(scanf("%d", &n)==1)
{
bpm.init(n, 3*n);
int cnt=0;
for(int i=1;i<=n;i++)
{
LL ta, tb;scanf("%lld%lld", &ta, &tb);
ds[i].a=ta, ds[i].b=tb;
if(mp.find(ta+tb)!=mp.end())
bpm.addEdge(i, mp[ta+tb]);
else
mp[ta+tb]=++cnt, bpm.addEdge(i, cnt), has[cnt]=ta+tb;
if(mp.find(ta-tb)!=mp.end())
bpm.addEdge(i, mp[ta-tb]);
else
mp[ta-tb]=++cnt, bpm.addEdge(i, cnt), has[cnt]=ta-tb;
if(mp.find(ta*tb)!=mp.end())
bpm.addEdge(i, mp[ta*tb]);
else
mp[ta*tb]=++cnt, bpm.addEdge(i, cnt), has[cnt]=ta*tb;
}
vector<int> X, Y;
int res=bpm.solve();
if(res!=n)
{
printf("impossible\n");
}
else
{
for(int i=1;i<=n;i++)
{
int k=bpm.right[i];
LL res=has[k];
if(ds[i].a+ds[i].b==res)
{
printf("%lld + %lld = %lld\n", ds[i].a, ds[i].b, res);
}
else if(ds[i].a-ds[i].b==res)
{
printf("%lld - %lld = %lld\n", ds[i].a, ds[i].b, res);
}
else if(ds[i].a*ds[i].b==res)
{
printf("%lld * %lld = %lld\n", ds[i].a, ds[i].b, res);
}
}
}
}
return 0;
}
Assigning Workstations
题意好复杂。有无限台计算机,每个计算机初始都是上锁的。给一些科学家的使用计算机时间,为<开始时间,持续时间>。计算机k分钟没人用就会自动上锁。求admin可以节省的解锁次数。
其实思路还蛮简单。因为计算机是无限的,所以维护一个集合:储存每个计算机上次结束使用的时间。对任务按开始时间排序,每次找据开始时间k以内最远的计算机使用。
#include<bits/stdc++.h>
#define M(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MAXN=300007;
const int oo=0x3f3f3f3f;
typedef long long LL;
multiset<LL> se;
struct Time
{
LL st,ed;
Time(){}
Time(LL _a,LL _b)
{
st=_a;
ed=_b;
}
bool operator <(const Time& t)const
{
return st==t.st?ed<t.ed:st<t.st;
}
}t[MAXN];
int main()
{
int n;LL m;
while(scanf("%d%lld",&n,&m)==2)
{
se.clear();
for(int i=1;i<=n;i++)
{
LL t1,t2;
scanf("%lld%lld",&t1,&t2);
t[i].st=t1;t[i].ed=t1+t2;
}
sort(t+1,t+1+n);
se.insert(t[1].ed);
int res=0;
for(int i=2;i<=n;i++)
{
LL tmp=t[i].st-m;
multiset<LL>::iterator ite=se.lower_bound(tmp);
if(ite!=se.end())
{
if((*ite)<=t[i].st)
{
res++;
se.erase(ite);
}
}
se.insert(t[i].ed);
}
printf("%d\n",res);
}
return 0;
}
Kitchen Combinatorics
#include <bits/stdc++.h>
using namespace std;
struct dish{
vector<int> ind[89];
}D;
int brand[1005];
bool jg[89][89];
int main() {
int r,s,n,d,m;
cin>>r>>s>>m>>d>>n;
for(int i=1;i<=r;i++)
cin>>brand[i];
int tot,p;
memset(jg,0,sizeof jg);
for(int i=1;i<=s+m+d;i++){
cin>>tot;
for(int j=1;j<=tot;j++){
cin>>p;
D.ind[i].push_back(p);
}
}
int u,v;
for(int i=1;i<=n;i++){
cin>>u>>v;
if(u>v)swap(u,v);
jg[u][v]=1;
}
bool flag=0;
long long ans=0;
for(int i=1;i<=s && !flag;i++)
for(int j=s+1;j<=s+m && !flag;j++)
for(int k=s+m+1;k<=s+m+d&& !flag;k++){
long long tmp=1;
long double gh1=1.0,tsum=ans;
if(jg[i][k]==1)continue;
if(jg[j][k]==1)continue;
if(jg[i][j]==1)continue;
map<int,int> mp;
mp.clear();
for(u=0;u<D.ind[i].size();u++)
mp[D.ind[i][u]]=mp[D.ind[i][u]]+1;
for(u=0;u<D.ind[j].size();u++)
mp[D.ind[j][u]]=mp[D.ind[j][u]]+1;
for(u=0;u<D.ind[k].size();u++)
mp[D.ind[k][u]]=mp[D.ind[k][u]]+1;
for(u=0;u<D.ind[i].size();u++)
if(mp[D.ind[i][u]]==1)
tmp*=brand[D.ind[i][u]],
gh1*=brand[D.ind[i][u]];
else if(mp[D.ind[i][u]]>1)
tmp*=brand[D.ind[i][u]],
gh1*=brand[D.ind[i][u]],
mp[D.ind[i][u]]=0;
if(gh1>1e18 || tmp<0){
flag=1;
break;
}
for(u=0;u<D.ind[j].size();u++)
if(mp[D.ind[j][u]]==1)
tmp*=brand[D.ind[j][u]],gh1*=brand[D.ind[j][u]];
else if(mp[D.ind[j][u]]>1)
tmp*=brand[D.ind[j][u]],gh1*=brand[D.ind[j][u]],
mp[D.ind[j][u]]=0;
if(gh1>1e18 || tmp<0){
flag=1;
break;
}
for(u=0;u<D.ind[k].size();u++)
if(mp[D.ind[k][u]]==1)
tmp*=brand[D.ind[k][u]],gh1*=brand[D.ind[k][u]];
else if(mp[D.ind[k][u]]>1)
tmp*=brand[D.ind[k][u]],gh1*=brand[D.ind[k][u]],
mp[D.ind[k][u]]=0;
if(gh1>1e18 || tmp<0){
flag=1;
break;
}
if(tsum+gh1>1e18){
flag=1;
break;
}
ans+=tmp;
}
if(!flag)
cout<<ans<<endl;
else
cout<<"too many"<<endl;
return 0;
}
Debugging
#include <bits/stdc++.h>
using namespace std;
long long n,r,p;
long long g[1000007]={0};
long long f(long long n){
long long ans=1e18;
if(n==0||n==1)return 0;
if(g[n])return g[n];
for(int i=1;i<n;i++)
ans=min(ans,f(n/(i+1)+((n%(i+1))?1:0))+i*p+r);
return g[n]=ans;
}
int main() {
memset(g,0,sizeof g);
cin>>n>>r>>p;
if(n==1LL||n==0){
puts("0");
return 0;
}
printf("%I64d\n",f(n));
return 0;
}
Cleaning Pipes
给定w个井口和p条管道,管道相交即代表有交点,现派出机器人进入若干管道进行清理交点,相交的管道之间最多允许存在一个机器人,问能否派出机器人将所有节点进行清理,且满足限制。
将管道抽象成点,如果管道之间存在交点则进行连边,所以问题就转化为了寻找一些点覆盖所有边且这些点之间不存在连边。从而问题就再次变成了判断连通图是否为二分图。
代码太长了,不贴了。
Guessing Camels
给三个序列,每个长n。问三个序列中相对位置相同的数对有多少对。
处理出每一个数在三个排列中的位置,就形成了n个三维点对
然后就是一个三维偏序问题了,用cdq分治+bit求解
裸地cdq。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=2e5+5;
int n, maxVal;
struct Operation
{
int a, b, c, w;
int f;//ans
bool operator <(const Operation &r)const
{
//return a<r.a || (a==r.a&&b<r.b) || (a==r.a&&b==r.b&&c<r.c);
return (a==r.a&&b==r.b) ? c<r.c : (a==r.a ? b<r.b : a<r.a);
}
}a[MAXN], t[MAXN];
LL c[MAXN];
inline int lowbit(int x) { return x&-x; }
inline void add(int p, int v) { for(;p<=maxVal;p+=lowbit(p)) c[p]+=v; }
inline LL sum(int p)
{
LL re=0;
for(;p;p-=lowbit(p)) re+=c[p];
return re;
}
int ans[MAXN];
LL rres;
void CDQ(int l, int r)
{
if(l==r) return;
int mid=(l+r)>>1;
CDQ(l, mid);CDQ(mid+1, r);
int i=l, j=mid+1, p=l;
while(i<=mid||j<=r)
{
if(j>r||(i<=mid&&a[i].b<=a[j].b)) add(a[i].c, a[i].w), t[p++]=a[i++];
else rres+=sum(a[j].c), t[p++]=a[j++];
}
for(int i=l;i<=mid;i++) add(a[i].c, -a[i].w);
for(int i=l;i<=r;i++) a[i]=t[i];
}
int ha[MAXN], hb[MAXN], hc[MAXN];
int main()
{
scanf("%d", &n);
for(int i=1;i<=n;i++)
{
int tmp;scanf("%d", &tmp);
ha[tmp]=i;
}
for(int i=1;i<=n;i++)
{
int tmp;scanf("%d", &tmp);
hb[tmp]=i;
}
for(int i=1;i<=n;i++)
{
int tmp;scanf("%d", &tmp);
hc[tmp]=i;
}
for(int i=1;i<=n;i++)
a[i].a=ha[i], a[i].b=hb[i], a[i].c=hc[i], a[i].w=1;
sort(a+1, a+1+n);
int p=1;
/*for(int i=2;i<=n;i++)
{
if(a[i].a==a[p].a&&a[i].b==a[p].b&&a[i].c==a[p].c) a[p].w++;
else a[++p]=a[i];
}*/
maxVal=MAXN-1;
rres=0;
CDQ(1, n);
printf("%lld\n", rres);
//system("pause");
}