第五届河南省大学生程序设计竞赛题解(第一次群赛兼妇女节专场)

A 奇怪的排序
暴力
范围<=50,直接暴力,用一个函数把范围内的数都反转,sort之解决
#include <bits/stdc++.h>
using namespace std;


int kase;
int l,r;
pair<int,int> arr[60];
int n;


int f(int x)
{
    int re=0;
    while(x)
    {
re*=10;
re+=x%10;
x/=10;
    }
    return re;
}


int main()
{
    //freopen("in.txt","r",stdin);
    cin>>kase;
    while(kase--)
    {
cin>>l>>r;
n=r-l+1;
for(int i=0;i<n;i++)
{
   arr[i].second=l+i;
   arr[i].first=f(l+i);
}
sort(arr,arr+n);
for(int i=0;i<n;i++)
{
   printf("%d",arr[i].second);
   if(i==n-1)
putchar(10);
   else
putchar(' ');
}
    }
    return 0;
}


B 最强DE 战斗力
大数+数学

因为战斗力为各部队乘积,所以大部队肯定要拆成小部队了(才看感觉是递归)。输出点小样例可以发现2,3的出镜率非常高。之后就集中注意力考虑拆成2,3了。n=2x+3y,max(z)=2^x*3^y=3^((log3(2)-2/3)x+n/3)。战斗力z和2的部队数负相关,所以尽量多拆3出来了,然后大数水过(bin神模板好,自己胡乱写的大数wa到哭,最后受不了了去网上复制的大数模板,太长所以这里不粘了)


C 试 制 品
很暴力的bfs
扫一下方程式,然后把里面的反应物和生成物分别提出来,每一个反应物都用数组储存参与了那些方程式。把初始拥有物品压入队列,然后暴力队列中物品参与的反应是否能够发生(反应物都可获得),反应成功的把还未拥有的生成物压入队列。
#include <bits/stdc++.h>
using namespace std;


const int maxn=2000;
int n,m;
string s;
map<string,int> num;
vector<int> in[maxn];
vector<int> out[maxn];
string str[maxn];
int cnt;
bool b[maxn];
queue<int> q;
vector<int> wh[maxn];
string ans[maxn];
int an;




void parse(int x)
{
    string t;
    int i=0;
    for(;;i++)
    {
if(s[i]=='+')
{
   if(!num.count(t))
   {
str[cnt]=t;
num[t]=cnt++;
   }
   in[x].push_back(num[t]);
   wh[num[t]].push_back(x);
   t.clear();
}
else if(s[i]=='=')
{
   if(!num.count(t))
   {
str[cnt]=t;
num[t]=cnt++;
   }
   in[x].push_back(num[t]);
   wh[num[t]].push_back(x);
   i++;
   t.clear();
   break;
}
else
   t+=s[i];
    }
    for(;i<s.size();i++)
    {
if(s[i]=='+')
{
   if(!num.count(t))
   {
str[cnt]=t;
num[t]=cnt++;
   }
   out[x].push_back(num[t]);
   t.clear();
}
else
   t+=s[i];
    }
   if(!num.count(t))
   {
str[cnt]=t;
num[t]=cnt++;
   }
   out[x].push_back(num[t]);
   t.clear();
}


void f(int x)
{
    for(int i=0;i<in[x].size();i++)
if(b[ in[x][i]]==0)
   return ;
    for(int i=0;i<out[x].size();i++)
    {
int &e =out[x][i];
if(b[e]==0)
{
   b[e]=1;
   q.push(e);
   ans[an++]=str[e];
}
    }
}


int main()
{
    //freopen("in.txt","r",stdin);
    cin>>n;
    for(int i=0;i<n;i++)
    {
cin>>s;
parse(i);
    }
    cin>>m;
    for(int i=0;i<m;i++)
    {
cin>>s;
int x=num[s];
b[x]=1;
q.push(x);
    }
    while(!q.empty())
    {
int x=q.front();
q.pop();
for(int i=0;i<wh[x].size();i++)
   f(wh[x][i]);
    }


    //for(int i=0;i<cnt;i++)
//cout<<'#'<<num[str[i]]<<str[i]<<endl;




    sort(ans,ans+an);
    cout<<an<<endl;
    for(int i=0;i<an;i++)
cout<<ans[i]<<endl;
    return 0;
}


D 遥控器
24K暴力
特判:如果y为个位数且y键完好1次直接按到

暴力:总共才100个台各种乱搞啊,如果--键好的,那么枚举所有能调到的台(3次按到),翻页键好的话计算从所有可能调到的台翻到y的次数

PS:原来的代码有漏洞被一位巨巨hack了orz,没有考虑到x=y的情况,此时应该输出0

#include <bits/stdc++.h>
using namespace std;


const int inf = 200;
int kase;
bool arr[13];
int x,y;
int ans;
bool b[100];


int f(int l,int r)
{
    if(r>l)
return r-l;
    return 100-l+r;
}


int main()
{
    //freopen("in.txt","r",stdin);
    cin>>kase;
    while(kase--)
    {
memset(b,0,sizeof(b));
for(int i=1;i<=3;i++)
   cin>>arr[i];
cin>>arr[11];
for(int i=4;i<=6;i++)
   cin>>arr[i];
cin>>arr[12];
for(int i=7;i<=9;i++)
   cin>>arr[i];
cin>>arr[10]>>arr[0];

cin>>x>>y;

if(x==y)

{

cout<<0<<endl;

continue;

}

ans=inf;
if(y<10 && arr[y])
{
   ans=1;
}
if(arr[10] && arr[y%10] && arr[y/10])
   ans=min(ans,3);
for(int i=0;i<=9;i++)
   b[i]=arr[i];
if(arr[10])
{
   for(int i=0;i<=9;i++)
if(b[i])
   for(int j=0;j<=9;j++)
if(b[j])
   b[i*10+j]=1;
}
if(arr[11])
{
   ans=min(ans,f(x,y));
   for(int i=0;i<=9;i++)
if(b[i])
   ans=min(ans,f(i,y)+1);
   for(int i=10;i<100;i++)
if(b[i])
   ans=min(ans,f(i,y)+3);
}
if(arr[12])
{
   ans=min(ans,f(y,x));
   for(int i=0;i<=9;i++)
if(b[i])
   ans=min(ans,f(y,i)+1);
   for(int i=10;i<100;i++)
if(b[i])
   ans=min(ans,f(y,i)+3);
}
if(ans==inf)
   ans=-1;
cout<<ans<<endl;
    }
    return 0;
}
E 奇妙的图案

此题比赛时候没做出来,后来看的bin神的题解:http://paste.ubuntu.com/10572491/

预处理一下哪两个点可以连接,之后就是dp水过

果然几何太渣啊。。。看完思路之后还是WA了N次才过

#include <bits/stdc++.h>
using namespace std;


const int maxn = 200;
const double eps = 1e-9;
const double INF = 1e10;
int x[maxn];
int y[maxn];
int rx[maxn];
int ry[maxn];
int n,m,r;
bool b[maxn][maxn];
int dp[maxn][maxn];


double dis(int x1,int y1,int x2,int y2)
{
    return sqrt(double(y1-y2)*(y1-y2)+double(x1-x2)*(x1-x2));
}


bool ok(int u,int v)
{
    double d;
    long long x1,x2,y1,y2;
    x1=x[u];
    x2=x[v];
    y1=y[u];
    y2=y[v];
    for(int ir=0;ir<m;ir++)
    {
if((x1-rx[ir])*(x1-x2)+(y1-ry[ir])*(y1-y2)<=0 || (x2-rx[ir])*(x2-x1)+(y2-ry[ir])*(y2-y1)<=0)
{
   d=min(dis(x1,y1,rx[ir],ry[ir]),dis(x2,y2,rx[ir],ry[ir]));
}
else
{
   if(x1==x2)
   {
d=abs(x1-rx[ir]);
   }
   else
   {
d=abs( (x2-x1)*(ry[ir]-y1) - (y2-y1)*(rx[ir]-x1) ) / sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
   }
}
    if(d < r+eps)
   return 0;
    }
    return 1;
}


int f(int u,int v)
{
    if(dp[u][v]!=-1)
return dp[u][v];
    dp[u][v]=0;
    for(int i=u+1;i<v;i++)
   dp[u][v]=max(dp[u][v],f(u,i)+f(i,v)+b[u][i]+b[i][v]);
    return dp[u][v];
}


int main()
{
    //freopen("in.txt","r",stdin);
    cin>>n>>m>>r;
    for(int i=0;i<n;i++)
scanf("%d%d",&x[i],&y[i]);
    for(int i=0;i<m;i++)
scanf("%d%d",&rx[i],&ry[i]);
    for(int i=0;i<n;i++)
for(int j=i+2;j<n;j++)
{
   b[i][j]=b[j][i]=ok(i,j);
}
    b[0][n-1]=0;
    memset(dp,-1,sizeof(dp));
    cout<<f(0,n-1);
    return 0;
}



F Metric Matrice
太暴力了,已经无话可说,秀个渣风格代码
#include <bits/stdc++.h>
using namespace std;


int kase ;
int n;
const int maxn=40;
int arr[maxn][maxn];
bool b[5];


int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d",&kase);
    while(kase--)
    {
scanf("%d",&n);
memset(b,0,sizeof(b));
for(int i=0;i<n;i++)
   for(int j=0;j<n;j++)
scanf("%d",&arr[i][j]);
for(int i=0;i<n;i++)
   if(arr[i][i])
   {
b[1]=1;
break;
   }
if(b[1])
{
   puts("1");
   continue;
}
for(int i=0;i<n;i++)
{
   for(int j=0;j<n;j++)
   {
if(i==j)
   continue;
if(arr[i][j]<=0)
{
   b[2]=1;
   break;
}
if(arr[i][j]!=arr[j][i])
{
   b[3]=1;
   break;
}
   }
   if(b[2]||b[3])
break;
}
if(b[2])
{
   puts("2");
   continue;
}
if(b[3])
{
   puts("3");
   continue;
}
for(int i=0;i<n;i++)
   for(int j=0;j<n;j++)
   {
if(i==j)
   continue;
for(int k=0;k<n;k++)
{
   if(k==i || k==j)
continue;
   if(arr[i][j]+arr[j][k]<arr[i][k])
   {
b[4]=1;
break;
   }
}
if(b[4])break;
   }
if(b[4])
{
   puts("4");
   continue;
} puts("0");
    }
    return 0;
}


G Divideing Jewels
又是很暴力的bfs
一看到题就各种琢磨暴力,从价值1的开始一层一层地枚举可能情况储存到数组里,看是否有解(为总价值的一半),然后没有悬念的T了(太暴力了捂脸)

之后想想价值不可能超过1000*10,加了个数组标记所有出现过的情况,水过

PS:总感觉这个方法是要T的,难道是数据太水,巨巨们都说是裸背包,准备要去看背包九讲补补课了orz

#include <bits/stdc++.h>
using namespace std;


int arr[11];
int sum;
bool ans;
int kase;
bool b;
bool sss[200000];
vector<int> vi;


int main()
{
    //freopen("in.txt","r",stdin);
    for(;;)
    {

bool ex=0;
for(int i=1;i<=10;i++)
{
   scanf("%d",&arr[i]);
   if(arr[i])
ex=1;
}
if(ex==0)
   break;
if(b)
   putchar(10);
b=1;
kase++;
printf("#%d:",kase);
sum=0;
for(int i=1;i<=10;i++)
   sum+=i*arr[i];
if(sum%2==1)
{
   puts("Can't be divided.");
   continue;
}
sum/=2;
ans=0;
vi.clear();
vi.push_back(0);
memset(sss,0,sizeof(sss));
sss[0]=1;
for(int i=1;i<=10;i++)
{
   int l=vi.size();
   if(ans)
break;
   for(int j=0;j<l;j++)
   {
if(ans)
   break;
for(int k=0;k<=arr[i];k++)
{
   int t=vi[j]+k*i;
   if(sss[t])
continue;
   if(t==sum)
   {
ans=1;
break;
   }
   vi.push_back(t);
   sss[t]=1;
}
   }
}
puts(ans?"Can be divided.":"Can't be divided.");
    }
    return 0;
}


H Interesting Punch-Bowl

比赛时候也没做出来。。后来看的胖巨的题解http://blog.csdn.net/kevin66654/article/details/44158575

优先队列,从高度最低的开始搜索

有点坑的就是多组数据没注意看题发现不了。。。又是WA得惊天动地


#include <bits/stdc++.h>
using namespace std;


int c,r;
const int maxn=350;
int arr[maxn][maxn];
bool b[maxn][maxn];
long long ans;


int x[4]={0,0,1,-1};
int y[4]={1,-1,0,0};


struct cmp
{
bool operator()(pair<int,int> a,pair<int,int> b)
{
    return arr[a.first][a.second]>arr[b.first][b.second];
}
};


priority_queue<pair<int,int>,vector<pair<int,int> >,cmp > q;


int main()
{
    //freopen("in.txt","r",stdin);
    while(cin>>c>>r)
    {
ans=0;
memset(b,0,sizeof(b));
    for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
   scanf("%d",&arr[i][j]);
    for(int i=0;i<=r+1;i++)
b[i][0]=b[i][c+1]=1;
    for(int j=0;j<=c+1;j++)
b[0][j]=b[r+1][j]=1;
    for(int i=1;i<=r;i++)
    {
q.push(make_pair(i,1));
q.push(make_pair(i,c));
b[i][1]=b[i][c]=1;
    }
    for(int j=2;j<c;j++)
    {
q.push(make_pair(1,j));
q.push(make_pair(r,j));
b[1][j]=b[r][j]=1;
    }
    while(!q.empty())
    {
pair<int,int> pi=q.top();
//cout<<pi.first<<' '<<pi.second<<endl;
q.pop();
for(int i=0;i<4;i++)
{
   int m=pi.first+x[i];
   int n=pi.second+y[i];
   if(b[m][n])
continue;
   if(arr[m][n]<arr[pi.first][pi.second])
   {
ans+=arr[pi.first][pi.second]-arr[m][n];
arr[m][n]=arr[pi.first][pi.second];
//cout<<m<<' '<<n<<' '<<ans<<endl;
   }
   b[m][n]=1;
   q.push(make_pair(m,n));
}
    }
    cout<<ans<<endl;
    }
    return 0;
}


总结:果然还是只会暴力暴力的。。。orz而且总是手残WA,继续努力

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值