A题:
阅读理解题,注意一下代码实现就好。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int n, m;
int a[100005];
int b[100005];
int main()
{
cin >> n >> m;
int odd= 0;
int even= 0;
up(i, 0, n)
{
scanf("%d", &a[i]);
if (a[i] & 1)odd++;
else even++;
}
int ans = 0;
up(i, 0, m)
{
scanf("%d", &b[i]);
if (b[i] & 1 && even)
{
even--;
ans++;
}
else if (!(b[i] & 1) && odd)
{
odd--;
ans++;
}
}
cout << ans << endl;
return 0;
}
B题:
贪心加上位操作加上模拟。
从右到左找到第一个0,从这里开始一直做题意给的操作直到符合题意。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int main()
{
int x;
cin >>x;
int t=0;
int temp = 0;
dwd(i, 31, 0)
{
if (x&(1 << i))
{
temp = i;
break;
}
}//找到最大的1的位置
//cout << ((1 << (temp + 1)) - 1);
vector<int >v;
up(i, 0, 40)
{
if (i & 1)
{
x++;
t++;
if (x == ((1 << (temp + 1)) - 1))
break;
}
else
{
dwd(i, temp, 0)
{
if (!(x&(1 << i)))
{
t++;
v.push_back(i+1);
x ^= ((1 << (i + 1)) - 1);
//cout << "x" << x << 'i' << i<<endl;
break;
}
}
if (x == ((1 << (temp + 1)) - 1))
break;
}
}
cout << t << endl;;
up(i, 0, v.size())
{
cout << v[i] << " ";
}
return 0;
}
C题:
数论,暴力
我们知道结论:gcd(a,b)=gcd(a,b-a)。
因为a%x=b%x=0,(a-b)%x=a%x-b%x=0=a%x=b%x。
其中b-a是固定的,所以对于求lcm(a,b),可以转换成1/gcd(a+k,b-a)* (a+k) *(b+k)
b-a不变,那么gcd要小,就要a+k是b-a的因数,对于每个分解,求min(lcm)
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
ll a, b;
ll dist;
ll ans = 0;
ll sum = 1e15;
ll gcd(ll a, ll b)
{
return b == 0 ? a : gcd(b, a%b);
}
int main()
{
cin >> a >> b;
if (a > b)swap(a, b);
if (b%a == 0) { cout << 0 << endl; return 0; }
dist = b - a;
if (dist < a)//a比dist大,直接就是dist的倍数就好了
{
cout << (dist - a % dist) % dist << endl;
return 0;
}
else
{
for (int i = 1; i*i <= dist; i++)
{
if (dist%i == 0)
{
ll temp = i - (a%i);
ll sumtemp = (a + temp)*(b + temp) / gcd(a + temp, b + temp);
if (sumtemp == sum)
{
if (temp < ans)ans = temp;
}
if (sumtemp < sum)
{
sum = sumtemp;
ans = temp;
}
temp = dist / i - (a % (dist / i));//另外一个也要尝试
sumtemp = (a + temp)*(b + temp) / gcd(a + temp, b + temp);
if (sumtemp == sum)if (temp < ans)ans = temp;
if (sumtemp < sum)sum = sumtemp, ans = temp;
}
}
cout << ans << endl;
}
return 0;
}
D题,树,dp
我们可以通过观察发现,其实当经历到树的某一层时,节点中只要左括号减去右括号相等的节点,接下来的叶子完全一样,所以有相当多的重复状态。
第二,从根往下走,要计算最多有多少个边,相当于计算从根节点往下,一层计算了边,一层没有,这样交替往下走直到走不下去。
因为是合法序列,所以一定是偶数层数,所以取1-2,3-4,5-6,。。。这样往下一定是最大的,相当于贪心一下。
然后我们就需要计算,1-2,3-4,5-6,有多少个边在里面。
记dp [i][j][k],i表示左括号,j表示右括号,这样i+j就能表示层数,其实k要不要无所谓。
我这里记录了一个k,k=1表示这个点我们取了,k=0表示没有取。(因为实际上就是计算偶数层有多少个节点。)
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int n;
ll dp[1005][1005][2];
ll mod = 1e9 + 7;
ll dfs(int i, int j, int k)
{
ll &ans = dp[i][j][k];
if (ans)return ans;
if (i < n)
{
int temp = k ? 0 : 1;
ans += dfs(i + 1, j, temp)+temp;
ans %= mod;
}
if (i > j)
{
int temp = k ? 0 : 1;
ans += dfs(i, j + 1, temp)+temp;
ans %= mod;
}
return ans;
}
int main()
{
cin >> n;
cout << 1+dfs(1, 0, 1) << endl;
}
E题。欧拉路径。
定义:
欧拉回路:每条边恰好只走一次,并能回到出发点的路径
欧拉路径:经过每一条边一次,但是不要求回到起始点
欧拉回路存在性的判定:
无向图
每个顶点的度数都是偶数,则存在欧拉回路。
有向图
每个节顶点的入度都等于出度,则存在欧拉回路。
欧拉路径存在性的判定:
有向图 : 图连通,当且仅当该图所有顶点数的度数为0,或者一个顶点的度数为1,另一个顶点的度数为-1,其他顶点的度数为0。
无向图:图连通,当且仅当该图所有顶点的度数为偶数,或者除了两个度数为奇数外其余的全是偶数。
对于这道题目,我们可以发现
对于一个二元组,(x,y)。
要么b[i]=x,c[i]=y,要么b[i]=y,c[i]=x。
所以这样,打乱过后的b,c数组,上下对于的两个数字,就是原数组的两个数字。
比如
3 4 5 6
4 5 6 7
那么3,4肯定是相邻两个数(原数组),4,5也是相邻,5 6,6 7 以此类推。
所以我们作图,把3-4连一条无向边,4-5连一条无向边,最后连接完毕,就可以发现,如果这个序列存在,那么从一个顶点出发,能够不重复的走边,遍历所有顶点,那么这个序列就是存在并且合法的。
我们就能想到,一笔画,即欧拉路径。
这里的条件刚好能够对应上欧拉路径。
因为一个数字要么不出现,要么出现就是偶数次的,因为 bi,bi+1,和bi+1,bi+2 ,bi+1出现两次。
所以除了头节点和尾节点,都是偶数的度,刚好和欧拉路径存在定理一样。
故我们建图,跑欧拉路径就好了。
用的是Hierholzer 算法。(需要先离散化一下,要不然数组放不下)
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
const int N = 2e5+10;
int n;
multiset<int > to[N];//用multiset方便查找和删除
int a[N], b[N],c[N],d[N], lisan[2*N];
int val[N];
int cnt = 0;
vector<int >vec;
void dfs(int v)
{
if (val[v] == 0) { vec.push_back(v); return; }
for (auto i = to[v].begin(); i != to[v].end(); i = to[v].begin())
{
int u = *i;
to[v].erase(i);
to[u].erase(to[u].find(v));
val[v]--;
val[u]--;
dfs(u);
}
vec.push_back(v);
}
int main()
{
n = read();
up(i, 0, n - 1)
{
a[i] = read();
lisan[cnt++] = a[i];
}
up(i, 0, n - 1)
{
b[i] = read();
lisan[cnt++] = b[i];
}
up(i, 0, n - 1)
{
if (a[i] > b[i])
{
cout << "-1" << endl;
return 0;
}
}
sort(lisan, lisan +cnt);
cnt = unique(lisan, lisan + cnt)-lisan;
up(i, 0, n-1)
{
c[i] = lower_bound(lisan, lisan + cnt, a[i]) - lisan;
d[i] = lower_bound(lisan, lisan + cnt, b[i]) - lisan;
}
up(i, 0, n-1)
{
to[c[i]].insert(d[i]);
to[d[i]].insert(c[i]);
val[c[i]]++;
val[d[i]]++;
}
int temp[N];
int tcnt=0;
up(i, 0,cnt)
{
if (val[i] % 2)temp[++tcnt] = i;
// cout << val[i] << endl;
}
if (tcnt != 0 && tcnt != 2) { cout << "-1" << endl; return 0; }
if (tcnt == 0)dfs(0);
else dfs(temp[1]);
if (vec.size() != n) { cout << "-1" << endl; return 0; }
up(i, 0, vec.size())
{
cout << lisan[vec[i]] <<" ";
}
return 0;
}