B - Make Numbers
题目
就是给你四个数字,范围是1~9,每个字母使用一次,可以组成123位数,求出使用+、-、*之后所有可能的结果
思路
一开始想了一下准备列举所有情况,后来放弃了(还好
然后后来模拟的时候有一些情况也没有考虑全面,主要是不会使用这个函数
补充知识点:
next_permutation()函数实现全排列
以三个字符为例:{a,c,b}
有六个排列组合:abc,acb,bac,bca,cab,cba,并根据less-than操作符做字典顺序(lexicographical)的排序,abc的next就是acb,如果没有的话,就直接跳出循环,
需要注意的是要先使用sort排序之后再使用,否则得到的答案是从当前的序列开始的
代码
#include<bits/stdc++.h>
using namespace std;
int a[4], t;
set<int> s;
set<int>::iterator itt;
void cal2(int a, int b)
{
t = a + b;
if (t >= 0)
s.insert(t);
t = a * b;
if (t >= 0)
s.insert(t);
t = a - b;
if (t >= 0)
s.insert(t);
}
void cal3(int a, int b, int c)
{
t = a + b + c;
if (t >= 0)
s.insert(t);
t = a + b - c;
if (t >= 0)
s.insert(t);
t = a + b * c;
if (t >= 0)
s.insert(t);
t = a - b + c;
if (t >= 0)
s.insert(t);
t = a - b - c;
if (t >= 0)
s.insert(t);
t = a - b * c;
if (t >= 0)
s.insert(t);
t = a * b + c;
if (t >= 0)
s.insert(t);
t = a * b - c;
if (t >= 0)
s.insert(t);
t = a * b * c;
if (t >= 0)
s.insert(t);
}
void cal4(int a, int b, int c, int d)
{
t = a + b + c + d;
if (t >= 0)
s.insert(t);
t = a + b + c - d;
if (t >= 0)
s.insert(t);
t = a + b + c * d;
if (t >= 0)
s.insert(t);
t = a + b - c + d;
if (t >= 0)
s.insert(t);
t = a + b - c - d;
if (t >= 0)
s.insert(t);
t = a + b - c * d;
if (t >= 0)
s.insert(t);
t = a + b * c + d;
if (t >= 0)
s.insert(t);
t = a + b * c - d;
if (t >= 0)
s.insert(t);
t = a + b * c * d;
if (t >= 0)
s.insert(t);
t = a - b + c + d;
if (t >= 0)
s.insert(t);
t = a - b + c - d;
if (t >= 0)
s.insert(t);
t = a - b + c * d;
if (t >= 0)
s.insert(t);
t = a - b - c + d;
if (t >= 0)
s.insert(t);
t = a - b - c - d;
if (t >= 0)
s.insert(t);
t = a - b - c * d;
if (t >= 0)
s.insert(t);
t = a - b * c + d;
if (t >= 0)
s.insert(t);
t = a - b * c - d;
if (t >= 0)
s.insert(t);
t = a - b * c * d;
if (t >= 0)
s.insert(t);
t = a * b + c + d;
if (t >= 0)
s.insert(t);
t = a * b + c - d;
if (t >= 0)
s.insert(t);
t = a * b + c * d;
if (t >= 0)
s.insert(t);
t = a * b - c + d;
if (t >= 0)
s.insert(t);
t = a * b - c - d;
if (t >= 0)
s.insert(t);
t = a * b - c * d;
if (t >= 0)
s.insert(t);
t = a * b * c + d;
if (t >= 0)
s.insert(t);
t = a * b * c - d;
if (t >= 0)
s.insert(t);
t = a * b * c * d;
if (t >= 0)
s.insert(t);
}
int main()
{
cin >> a[0] >> a[1] >> a[2] >> a[3];
sort(a, a + 4);
do
{
cal2(a[0], a[1] *100 + a[2] * 10 + a[3]);
cal2(a[0] * 10 + a[1], a[2] * 10 + a[3]);
cal2(a[0] * 100 + a[1] * 10+a[2], a[3]);
cal3(a[0], a[1] * 10 + a[2], a[3]);
cal3(a[0], a[1], a[2] * 10 + a[3]);
cal3(a[0] * 10 + a[1], a[2], a[3]);
cal4(a[0], a[1], a[2], a[3]);
} while (next_permutation(a, a + 4));
// for (itt=s.begin() ;itt!=s.end();itt++)
// {
// cout<<*itt<<' ';
// }
cout << s.size() << endl;
return 0;
}
还有一个看到的很简单的代码,值得学习
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int maxl=1e5+10;
int n,ans;
bool vis[maxl];
map<pair<vector<int>,int>,bool> mp;
inline void dfs(int stp,vector<int> a)
{
if(mp[{a,stp}])
return;
mp[{a,stp}]=true;
int l=a.size();
if(l==1)
{
if(a[0]>=0 && !vis[a[0]])
{
vis[a[0]]=true,++ans;
//printf("%d\n",a[0]);
}
return;
}
if(stp==1 || stp==2) //表示*
{
dfs(stp+1,a);
if(stp==1 && l==2)
return;
for(int i=0;i<l-1;i++)
{
vector<int> tmp;
for(int j=0;j<i;j++)
tmp.pb(a[j]);
if(stp==1)
{
if(a[i+1]<10)
tmp.pb(a[i]*10+a[i+1]);
else
tmp.pb(a[i]*100+a[i+1]);
}
else
tmp.pb(a[i]*a[i+1]);
for(int j=i+2;j<l;j++)
tmp.pb(a[j]);
dfs(stp,tmp);
}
}
if(stp==3) //+-的组合
{
vector<int> tmp;
tmp.pb(a[0]+a[1]);
for(int i=2;i<l;i++)
tmp.pb(a[i]);
dfs(3,tmp);
tmp[0]=a[0]-a[1];
dfs(3,tmp);
}
}
int main()
{
vector<int> a;
for(int i=1;i<=4;i++)
{
int x;scanf("%d",&x);
a.pb(x);
}
sort(a.begin(),a.end());
do
dfs(1,a);
while(next_permutation(a.begin(),a.end()));
printf("%d\n",ans);
/*for(int i=0;i<=1e4;i++)
if(vis[i])
printf("%d\n",i);
*/
return 0;
}
E - Optimization for UltraNet
题目
OMG,这个题怎么这么长啊啊啊啊,孩子读不懂啊啊啊啊,呜呜呜呜哭晕(っ °Д °;)っ(对我的六级十分担忧。。)
要求:
- n个点,n-1条路
- 1有很多种情况,要选择:最小的那条路,要尽可能地大的那种
- 线路总和最少,最大的边要尽量小
- 计算总和的方法:当前边的权值为w,左侧连接的子树大小为a,右侧子树的大小为b,它的贡献就是w * a * b
思路
- 把边排序之后,二分枚举,看是否能组成一棵树
- dfs
代码
//不想写了。。先存着吧
#include <bits/stdc++.h>
#define maxx 1001
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
//记录状态
struct node
{
int x, y, l;
} road[maxx<<1];
bool cmp(node &a, node &b)
{
return a.l < b.l;
}
ll sum;
int n, m;
int fa[maxx],dis[maxx];
//连接
struct edge
{
int x,y,l;
}e[maxx];
int find(int x)
{
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
bool Union(int x, int y)
{
int fx = find(x);
int fy = find(y);
if (fx != fy)
{
fa[fy] = fx;
return true;
}
return false;
}
void add(int x, int y, int l)
{
}
bool check(int mid, int f)
{
for (int i = 1; i <= n; ++i)
{
fa[i] = i;
}
int cnt = 0;
for (int i = mid; i <= m; ++i)
{
if (Union(road[i].x, road[i].y))
{
cnt++;
if (f==1)
{
add(road[i].x,road[i].y,road[i].l);
add(road[i].y,road[i].x,road[i].l);
}
}
}
return cnt == n - 1;
}
void dfs(int x,int k)
{
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; ++i)
{
cin >> road[i].x >> road[i].y >> road[i].l;
}
sort(road + 1, road + 1 + m, cmp);
int l = 1, r = m, mid, ans;
while (l <= r)
{
mid = (l + r) / 2;
if (check(mid,0))
{
l = mid + 1;
ans = mid;
}
else
r = mid - 1;
}
check(ans,1);
ll res=0;
for (int i = 1; i <= n; ++i)
{
dis[i] = inf;
dfs(i,-1);
res+=sum;
sum=0;
}
return 0;
}
/*
*
5 7
1 2 6
1 4 12
1 3 10
2 4 8
2 5 3
3 4 4
4 5 2
*/
G - August
题目
给定ab,求下面函数围成的面积
思路
一个圆+两个长方形(arcsin,arccos是关于(a,-b)对称的)
J - Goodbye**
题目
游戏规则:
两个人轮流选择一个数字然后claim it(一开始看题的时候,布吉岛claim是什么意思),两人人轮流选择上一个人选的数字的真因数(In the next rounds, player should choose one positive proper divisor of the number claimed in the previous round.),最后无法作出选择的那个人赢得比赛
现在,要让Chino赢而且选择尽可能大的数字,要告诉他第一轮应该选择什么数字
▶ claim
获得、赢得 She has finally claimed a place on the team.
思路
倒推一下:
Chino win→上一个人选择的是质数→Chino的数字是由质数组成的,下一个人只能选质数
(谁先拿到质数谁就输了)
代码
#include <iostream>
using namespace std;
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
int sum = 0;
int ans[100010];
for (int i = n / 2 + 1; i >= 2; i--)
{
if (n % i == 0)
{
sum++;
ans[sum] = i;
n = i;//替换n
}
}
if (sum == 0)
cout << 0 << endl;
if (sum == 1)
cout << "-1" << endl;
if (sum >= 2)
cout << ans[sum - 1] << endl;
}
return 0;
}