排名依旧是倒数,感觉疲劳呈n²递增,脑子想不出东西......
没关系,我爱补题!!!
C - Many Formulas (atcoder.jp)
好吧,我好像并没有完全学会二进制枚举....至少现在我不知道什么时候用它,
为什么使用二进制枚举
二进制可以解决有的时候很难用循环把所有的情况都表示出来的这个问题;
这道题的意思是给你一个有数字组成的字符串,任意添加+号使他变成一个计算式并且累加所有计算结果,列如:字符串123,、
就可以写成123
1+23
12+3
1+2+3
最终结果:123+1+23+12+3+1+2+3=168;
我们就要枚举加号的位置:
代码模拟:
对0到2进行二进制枚举
000:125
001:12+5
010: 1+25
011: 1+2+5
这里没有100是因为代码中枚举的范围是小于m的;
#include<bits/stdc++.h>
using namespace std;
#define int long long
string s;
int ans=0;
signed main(){
cin>>s;
int l=s.size();
int m=1<<(l-1);//如果有l个数字就有l-1个加号;
for(int i=0;i<m;i++)//开始二进制枚举
{
int t=s[0]-'0';
for(int j=0;j<l;j++)//遍历字符串
{
if(j==l-1 || i&1<<j) //遇上加号的时候和枚举到字符串最后一个的时候,就得加数;
{
ans+=t;
t=0;//更新下一个要加的数,t需要清0:
if(j==l-1) {
break;
}
}
t=t*10+s[j+1]-'0';
}
}
cout<<ans<<endl;
return 0;
}
再来亿道二进制枚举,我现在强得可怕!!!<(-︿-)>
C - Tak and Cards (atcoder.jp)
我一开始的思路像第一题一样枚举所有组合可能,即n个数里面选择k个数,发现好难,脑子罢工...
这个也是枚举,不过用的是动态规划来枚举,
看的别人的题解,说的是用一个三维数组来枚举,dp[i][j][k],前 i 个数总和为 j 的方案数 k 的,这里用到了滚动数组,所以呈现的是二维数组,
k-a[i]表示的是没加a[i]的数,比如
n=4 A=8;7 9 8 9
如果要得到15,就是d[2][15]=d[2][15]+d[1][15-8]=d[2][15]+d[1][7];
现在dp[j][k]就是已经存在的方案数加上(之前算过的),加了a[i]就变为k的方案数;
上面的例子中dp矩阵长这样
从第0行开始
还抽象,想了一个4个小时。。。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxm = 1e6 + 5;
int d[55][55 * 55]; // DP数组,d[i][j]表示长度为i的子序列和为j的方案数
int a[maxm]; // 存储输入的数组
int n, A; // n是数组a的长度,A是题目给定的参数
void solve() {
cin >> n >> A; // 输入数组长度n和参数A
for (int i = 1; i <= n; i++) {
cin >> a[i]; // 输入数组a的元素
}
d[0][0] = 1; // 初始化,长度为0的子序列(即空序列)和为0的方案数为1
// 动态规划过程
for (int i = 1; i <= n; i++) { // 遍历数组中的每个元素
for (int j = i; j >= 1; j--) { // 对于每个可能的子序列长度j(从当前元素开始到1)
for (int k = n * A; k >= a[i]; k--) {// 遍历所有可能的和k(从大到小,避免重复计算)
//cout<<k-a[i]<<" ";
d[j][k] += d[j - 1][k - a[i]]; // 状态转移方程,表示当前元素加入后,新的方案数
}
}
cout<<endl;
}
int ans = 0; // 初始化答案
for (int i = 1; i <= n; i++) {
ans += d[i][i * A];
}
cout << ans << endl;
}
signed main() {
ios::sync_with_stdio(0); cin.tie(0);
solve();
return 0;
}
多源最短路,Floyd算法,学了就能做;
#include<bits/stdc++.h>
using namespace std;
#define int long long
int mp[11][11];
int tu[202][202];
signed main(){
int n,m;
cin>>n>>m;
for(int i=0;i<=9;i++){
for(int j=0;j<=9;j++){
cin>>mp[i][j];
}
}
for(int k=0;k<=9;k++){
for(int i=0;i<=9;i++){
for(int j=0;j<=9;j++){
mp[i][j]=min(mp[i][k]+mp[k][j],mp[i][j]);
}
}
}
//cout<<mp[8][1]<<endl;
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>tu[i][j];
if(tu[i][j]==1||tu[i][j]==-1){
continue;
}
else ans+=mp[tu[i][j]][1];
}
}
cout<<ans<<endl;
return 0;
}
D - Coloring Edges on Tree (atcoder.jp)
这题有点思路,但不多;
求最少需要几种颜色,就求度数最大的顶点。难点在于记录每天边染的什么颜色;
一开始我想的是从起点1开始,往下染色,标记每个顶点除了根节点在向下染色之前已经被哪种颜色染过了。在其子节点染色的时候,从1,2,3,.....n染色,当现在需要序号 i 染色,但之前已经已经用过了就跳过,然后在继续加1染色。,
但是好像这么写漏掉了什么点,
别人的题解:
用最少的颜色上色,使得连在一个点上的所有边颜色都不同
就是最大的度数,难点在于上色,可以这么考虑:
找到度数最大的点,以此点为起点进行 BFS,设一个点的颜色数组,起点的颜色置为 0 00,当以某个点 BFS 时,所有与之相连的点都不能与其同色
每次 BFS,都从 1 颜色开始上色,若与起点颜色重复或者某点上色完毕颜色都要加 1 取模
但是题目要求输出每条边的颜色,我们可以用 map+pair 记录每条边的颜色,不难发现边的颜色和 BFS 过程中某点上的颜色相同
WA:
#include<bits/stdc++.h>
using namespace std;
#define int long long
vector<int>a[100005];
int b[100005];
int maxx=0;
int vis[100005];
int ans[100005];
signed main(){
int n;
cin>>n;
for(int i=1;i<=n-1;i++){
int x,y;
cin>>x>>y;
a[x].push_back(y);
if(a[x].size()>maxx)maxx=a[x].size();
a[y].push_back(x);
if(a[y].size()>maxx)maxx=a[y].size();
}
int step=0;
int cnt=1;
b[1]=-1;
for(int i=1;i<=n;i++){
cnt=1;
for(auto p:a[i]){
if(cnt==b[i])cnt++;//如果此数字代表的颜色之前已经被用过了
if(b[p]==0){//如果此节点没有被染色
b[p]=cnt;
ans[++step]=cnt;
cnt++;
}
}
}
cout<<maxx<<endl;
for(int i=1;i<=step;i++){
cout<<ans[i]<<endl;
}
return 0;
}
正确的代码和我的很像,它使用度数最多的点作为根节点,我是用的1,不过我没有用BFS,我应该是漏掉顶点了?
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
vector<int>G[N];
int vis[N],color[N],n,u,v,mx=0,s;
struct node{
int u,v;
};
vector<node>edge;
map<pair<int,int>,int>m;
void bfs(int s){
queue<int>q;
q.push(s);
vis[s]=1;
while(!q.empty()){
int u=q.front();
q.pop();
int c=1;
for(auto v:G[u]){
if(!vis[v]){
q.push(v);
if(c==color[u])c++;
color[v]=c;
m[{min(u,v),max(u,v)}]=c;
c++;
vis[v]=1;
}
}
}
}
int main(){
cin>>n;
for(int i=0;i<n-1;i++){
cin>>u>>v;
edge.push_back({u,v});
G[u].push_back(v);
G[v].push_back(u);
}
for(int i=1;i<=n;i++){
if(G[i].size()>mx){
mx=G[i].size();
s=i;
}
}
bfs(s);
color[s]=0;
cout<<mx<<endl;
for(auto i:edge) cout<<m[{min(i.u,i.v),max(i.u,i.v)}]<<endl;
return 0;
}
这道题我的思路是存储一个二维数组表示所找到的点在不在坐标当中。
如果不在,当前节点就是曼哈顿距离最小的点:
就是对原坐标bfs (x+1,y),(x-1,y) ; (x,y+1);(x,y-1)
(x-1,y-1),(x+1,y+1); 搜完发现都在坐标当中就将1换成2;但是n<=2e5;
这题的解法很巧妙:
对于这n 个点(便于区分,称它们为有效点),我们发现,对于有效点x ,除非周围都被其他有效点包围,否则它的exclueded point只要取它周边的相连的非有效点即可,此时距离最小。
那么对于剩下那些被其他有效点包围的 有效点,我们怎么求它的exclueded point呢?我们bfs搜索它四周的有效点即可
#include<bits/stdc++.h>
using namespace std;
int dx[] = {0, 0, -1, 1};
int dy[] = {-1, 1, 0, 0};
int main() {
int n;
scanf("%d", &n);
vector<pair<int, int>> a(n);
for (auto &v : a) scanf("%d %d", &v.first, &v.second);
set<pair<int, int>> st(a.begin(), a.end());
map<pair<int, int>, pair<int, int>> ans;
queue<pair<int, int>> q;
for (auto v : a) {
int x = v.first, y = v.second;
for (int i = 0; i < 4; ++i) {
int nx = x + dx[i], ny = y + dy[i];
if (st.count({nx, ny})) {
continue;
}
ans[{x, y}] = {nx, ny};
q.push({x, y});
break;
}
}
while (!q.empty()) {//我们应该查找非有效点-点外的有效点,如果是非有效点,还得向外找,所以我们就直接查找有效点;
int x = q.front().first, y = q.front().second;
q.pop();
for (int i = 0; i < 4; ++i) {
int nx = x + dx[i], ny = y + dy[i];
if (!st.count({nx, ny}) || ans.count({nx, ny})) {
continue;
}
//该点不在答案中,并且该点是各处的点-没有找到答案的点
ans[{nx, ny}] = ans[{x, y}];//我们要找的就是原来给出的点中谁是有效点。存进去
q.push({nx, ny});
}
}
for (auto v : a) {
auto it = ans[{v.first, v.second}];
printf("%d %d\n", it.first, it.second);
}
return 0;
}