您的位置:首页 > 其它

2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest

2018-02-01 19:44 471 查看
A. Auxiliary Project

题意:在LED灯中点亮0-9中的每个数字都需要相应数目的灯管,现在给定灯管数目,将点亮的数字相加,问这个总和最大是多少。

题解:这个就是完全背包。

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 1000050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

int n;
int w[10]={6,2,5,5,4,5,6,3,7,6};
int dp[maxn];

int main()
{
//freopen("auxiliary.in","r",stdin);
//freopen("auxiliary.out","w",stdout);
scanf("%d",&n);
memset(dp,-1,sizeof(dp));
dp[0]=0;
for(int i=0;i<=n;i++)
{
for(int j=0;j<10;j++)
{
if(dp[i-w[j]]>=0&&i-w[j]>=0)
dp[i]=max(dp[i],dp[i-w[j]]+j);
}
}
printf("%d\n",dp
);
return 0;
}


B. Boolean Satisfiability

题意:26个字母的大小写分别代表一种指令,现在有一个表达式只有由这52种指令、逻辑非、逻辑或组成,要求这个表达式的值为真,问有多少种设定每种指令真值的方案。

题解:首先找出表达式中一共出现了多少种不同的指令,设数目为n。使表达式为真即至少有一个为真。如果某种指令和它的逆同时出现在表达式中,那么不管这个指令是真是假,二者总有一个为真。因此方法是查询这n种指令中有没有原指令和逆同时出现的情况,若有则结果为2^n,否则就要去掉所有指令都为假的情况,结果为2^n-1。

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 1050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

char s[maxn];
int n,vis[maxn],flag[maxn];

int main()
{
//freopen("boolean.in","r",stdin);
//freopen("boolean.out","w",stdout);
while(scanf("%s",s)!=EOF)
{
n=strlen(s);
memset(vis,0,sizeof(vis));
memset(flag,0,sizeof(flag));
for(int i=0;i<n;i++)
{
if(s[i]=='|')
continue;
else if(s[i]=='~')
{
vis[s[i+1]]++;
i++;
}
else flag[s[i]]++;
}
ll ans=1;
int tmp=1;
for(int i=0;i<maxn;i++)
{
if(flag[i]&&vis[i])tmp=0;
if(flag[i]||vis[i])ans<<=1;
}
cout<<ans-tmp<<endl;
}
return 0;
}


C. Consonant Fencity

题意:给定一个由小写字母组成的字符串,现将其中的某几种字母由小写变为大写,使得满足如下条件的相邻字符对数目最大:两个字母都为辅音,且其中一个是大写,另一个是小写,将w和y视为元音。求变换之后的字符串。

题解:先预处理字符串,记录下所有两个辅音字母相邻的状态数目。然后O(2^19)状态压缩枚举所有辅音字母的大小写即可。

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 1000050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

char s[maxn];
int n;
int flag[25];
int num[25][25];
map<char,int>m;

int main()
{
//freopen("consonant.in","r",stdin);
//freopen("consonant.out","w",stdout);
scanf("%s",s);
int n=strlen(s);
int no=1;
for(int i=0;i<26;i++)
{
if(i==0||i==4||i==8||i==14||i==20||i==22||i==24)
continue;
char c='a'+i;
m[c]=no++;
}
memset(num,0,sizeof(num));
for(int i=1;i<n;i++)
{
if(m[s[i-1]]&&m[s[i]])
num[m[s[i-1]]][m[s[i]]]++;
}
int maxx=0,k=-1;
for(int i=0;i<(1<<19);i++)
{
int tmp=i;
for(int j=0;j<19;j++)
{
flag[j]=tmp%2;
tmp/=2;
}
int cnt=0;
for(int j=1;j<=19;j++)
{
for(int k=1;k<=19;k++)
{
if(k==j)continue;
if(flag[k]+flag[j]==1)
cnt+=num[j][k];
}
}
if(maxx<cnt)
{
maxx=cnt;
k=i;
}
}
for(int i=0;i<19;i++)
{
flag[i]=k%2;
k/=2;
}
for(int i=0;i<n;i++)
{
if(flag[m[s[i]]])
s[i]-=32;
}
printf("%s\n",s);
return 0;
}


E. Equal Numbers

题意:给出一个数组a1~an,现在可以进行n次操作,每次操作都可以令数组中的某一些数乘上某一个相同的数字,问每次操作后数组的不同数字数目最小是多少。

题解:对于每一个数,在操作时本着减少数字种类的原则,都可以变成一个存在于这个数组中的倍数或者Lcm(a1,a2…an)。分别存储每种数字的数目和每种其他数倍数的数目,对于第i次操作,首先要满足从初始变化到此处的操作不超过i次,然后将某个数变为其倍数用dp的思想分别在原数字和倍数上各扫一遍维护剩下的数字数目握草我说的是些啥还是看写的代码吧orz。。。

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 300050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

int n;
int a[maxn],dp[maxn];
vector<int>x,y;
map<int,int>m;
map<int,int>::iterator cnt;

int main()
{
//freopen("equal.in","r",stdin);
//freopen("equal.out","w",stdout);
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
m[a[i]]++;
}
int top=1000000;
x.clear(),y.clear();
for(cnt=m.begin();cnt!=m.end();)
{
int u=cnt->first;
x.push_back(cnt->second);
for(int j=u*2;j<=top;j+=u)
{
if(m.count(j))
{
y.push_back(cnt->second);
break;
}
}
cnt++;
}
int tmp=m.size();
memset(dp,63,sizeof(dp));
dp[0]=tmp;
sort(x.begin(),x.end());
sort(y.begin(),y.end());
int sum=0,len=y.size();
for(int i=0;i<len;i++)
{
sum+=y[i];
dp[sum]=min(dp[sum],tmp-i-1);
}
sum=0,len=x.size();
for(int i=0;i<len;i++)
{
sum+=x[i];
dp[sum]=min(dp[sum],tmp-i);
}
printf("%d",dp[0]);
for(int i=1;i<=n;i++)
{
dp[i]=min(dp[i],dp[i-1]);
printf(" %d",dp[i]);
}
printf("\n");
return 0;
}


I. Intelligence in Perpendicularia

题意:在直角坐标系里搭了一圈篱笆,问有多长的篱笆是从外面在四个方向都看不见的。

题解:用篱笆的总长度减去包围这圈篱笆的矩形的周长。

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 1050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

int n;
int x[maxn],y[maxn];

int main()
{
//freopen("intel.in","r",stdin);
//freopen("intel.out","w",stdout);
scanf("%d",&n);
int maxx=-INF,minx=INF;
int maxy=-INF,miny=INF;
for(int i=0;i<n;i++)
{
scanf("%d%d",&x[i],&y[i]);
maxx=max(maxx,x[i]);
maxy=max(maxy,y[i]);
minx=min(minx,x[i]);
miny=min(miny,y[i]);
}
int sum=0;
x
=x[0],y
=y[0];
for(int i=0;i<n;i++)
sum+=(abs(x[i]-x[i+1])+abs(y[i]-y[i+1]));
sum-=(2*(maxx-minx+maxy-miny));
if(maxx==minx||maxy==miny)sum=0;
printf("%d\n",sum);
return 0;
}


K. Kotlin Island

题意:在一个n*m的平面上横竖挖沟,问能否分成k块,若能则输出挖后的地图。

题解:n*m的空地最多能挖成((n-1)/2+1)*((m-1)/2+1)块,直接0(1e4)枚举一遍行和列就行了。注意行或列为1的情况。

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 1050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

int n,m,w;

void solve(int p,int q)
{
int x=p-1,y=q-1;
for(int i=0;i<x;i++)
{
for(int j=0;j<y;j++)
printf(".#");
for(int j=2*y;j<m;j++)
printf(".");
printf("\n");
for(int j=0;j<m;j++)
printf("#");
printf("\n");
}
for(int i=x*2;i<n;i++)
{
for(int j=0;j<y;j++)
printf(".#");
for(int j=2*y;j<m;j++)
printf(".");
printf("\n");
}
}

int main()
{
//freopen("kotlin.in","r",stdin);
//freopen("kotlin.out","w",stdout);
scanf("%d%d%d",&n,&m,&w);
int x=(n-1)/2,y=(m-1)/2;
bool flag=0;
for(int i=0;i<=x;i++)
{
if(w%(i+1)==0&&w/(i+1)<=y+1)
{
flag=true;
solve(i+1,w/(i+1));
break;
}
}
if(!flag)
printf("Impossible\n");
return 0;
}


L. Little Difference

题意:将一个数分解为若干个数相乘的形式,其中这些数的最大值与最小值最多相差1,求所有的分解方式,若有无穷多种分解方式则输出-1。

题解:如果这个数是2^n的形式就有无穷多种分解方式,否则都可以写成a^x或a^x(a+1)^y的形式。枚举x和y然后二分计算a即可。

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 105
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

ll n;
struct node
{
int x,y;
ll a;
};
vector<node>e;

bool judge(ll a,int x,int y,int flag)
{
ll ans=1;
for(int i=0;i<x;i++)
{
if((long double)ans*a>n)return 0;
ans*=a;
}
for(int i=0;i<y;i++)
{
if((long double)ans*(a+1)>n)return 0;
ans*=(a+1);
}
if(flag)return ans<=n;
return ans==n;
}

int main()
{
//freopen("little.in","r",stdin);
//freopen("little.out","w",stdout);
scanf("%I64d",&n);
for(int i=0;i<63;i++)
{
if((1LL<<i)==n)
{
printf("-1\n");
return 0;
}
}
for(int i=1;i<63;i++)
{
for(int j=1;j<=i;j++)
{
ll l=1,r=n+1;
while(l+1<r)
{
ll mid=(l+r)>>1;
if(judge(mid,j,i-j,1))
l=mid;
else
r=mid;
}
if(judge(l,j,i-j,0))
{
node tmp;
tmp.x=j,tmp.y=i-j,tmp.a=l;
e.push_back(tmp);
}
}
}
int len=e.size();
printf("%d\n",len);
for(int i=0;i<len;i++)
{
printf("%d",e[i].x+e[i].y);
for(int j=0;j<e[i].x;j++)
printf(" %I64d",e[i].a);
for(int j=0;j<e[i].y;j++)
printf(" %I64d",e[i].a+1);
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm-icpc