A. Consecutive Sum Riddle
题意
给定一个数n, n <= 1e18,要求找到一串连续的数使得这串数之和等于n
思路
水题,直接看代码吧
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <time.h>
using namespace std;
#define int long long
#define pii pair<int, int>
#define pdd pair<double, double>
#define SSS \
ios_base::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0);
#define caseT \
int t; \
cin >> t; \
while (t--)
const int N = 1e5 + 10, mod = 1e9 + 7;
void solve()
{
int n;
cin >> n;
cout << -(n - 1) << " " << n << endl;
}
signed main()
{
SSS;
caseT
{
solve();
}
return 0;
}
B - Special Numbers
题意
t组样例,每组给一个n和一个k,找出n的次幂之和的排列的第k小的数
思路
这题把k看成是二进制的数,例如n = 2, k = 12这组样例,k可以看做1100,即22 + 23,结果为12 ,所以使用快速幂解决
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <time.h>
using namespace std;
#define int long long
#define pii pair<int, int>
#define pdd pair<double, double>
#define SSS \
ios_base::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0);
#define caseT \
int t; \
cin >> t; \
while (t--)
const int N = 1e5 + 10, mod = 1e9 + 7;
int q_m(int a, int b) // a^b
{
int res = 1;
while (b)
{
if (b & 1)
{
res = (res * a) % mod;
}
a = (a * a) % mod;
b >>= 1;
}
return res;
}
void solve()
{
int n, m;
cin >> n >> m;
int ans = 0;
int cnt = 0;
while (m)
{
if(m & 1)
{
ans = (ans + q_m(n, cnt)) % mod; // 求和
}
m >>= 1;
cnt++;
}
cout << ans << endl;
}
signed main()
{
SSS;
caseT
{
solve();
}
return 0;
}
C. Make Them Equal
题意
给定字符串s和一个字符c,使得字符串全部变为字符c
在一次操作中,可以选择一个数字x(1≤x≤n), 对于每个位置i,其中i不能被x整除,用c替换si。
找出使所有字符都等于c和x-s所需的最小操作数,
思路
观察可知,最多操作2次即可使得所有字符都变成c,所以关键是要找出一次操作即可完成的位置
我的做法是找到所有字符等于c的位置,存到数组之中,从后往前依次遍历,找到一个位置就找当前位置*j的位置,看字符是否等于c,最坏时间复杂度为nlogn,对于此题完全够用
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <time.h>
using namespace std;
#define int long long
#define pii pair<int, int>
#define pdd pair<double, double>
#define SSS \
ios_base::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0);
#define caseT \
int t; \
cin >> t; \
while (t--)
const int N = 3e5 + 10, mod = 1e9 + 7;
int d[N]; // 存储字符等于c的位置
void solve()
{
int n;
char c;
cin >> n >> c;
string s;
cin >> s;
int res = 0;
int cnt = 0;
for (int i = 0; i < s.size(); i++)
{
if (s[i] == c)
{
d[++cnt] = i + 1;
}
}
if (cnt == n)
{
cout << 0 << endl;
}
else if (n - cnt > 1) // 如果当前有>=2个字符不等于c
{
int flag = 0;
for (int i = cnt; i >= 1; i--)
{
if (d[i] == 1)
continue;
for (int j = d[i]; j <= n; j += d[i])
{
if (s[j - 1] == c)
{
flag = j;
}
else
{
flag = 0;
break;
}
}
if (!flag)
{
continue;
}
else
{
cout << 1 << endl;
cout << flag << endl;
break;
}
}
if (!flag) // 找不到可以使得字符串全部更改为c的位置
{
cout << 2 << endl;
cout << n - 1 << " " << n << endl;
}
}
else // 由于n>=3,所以当只有一个的时候,随便找相邻或者最后即可
{
cout << 1 << endl;
if (s[n - 1] == c)
{
cout << n << endl;
}
else
{
cout << n - 1<< endl;
}
}
}
signed main()
{
SSS;
caseT
{
solve();
}
return 0;
}
D. The Number of Imposters
题意
在among us中,会有内奸和船员,我们需要对每个人的指认(a 指认 b 为船员或者内奸)进行判断,找到使得内奸最多的一种方式(防人之心不可无)
思路
可以使用二分图的做法找到是否有一种方式使得所有指认不相互矛盾,因为所有的指认可能连不成一张图,所有得用一种方法利于最后的统计,这里我使用了并查集,把相关身份信息与祖宗节点连接起来统计
那么说到二分图,其中一种做法是对图中的点依次进行编号,那么该怎么找到对应关系呢
稍加推理可以知道,如果a指认b为船员,那么a和b则是同一身份,否则为不同身份,那么对应到图里面,a->b如果为同一身份,那么此边权值为1,b的身份修改为a的身份,否则权值为0,b身份修改为与a敌对,再用dfs对图中各点进行搜索,依次找出单个并查集中出现次数最多的身份,相加即为答案
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <time.h>
using namespace std;
#define pii pair<int, int>
#define pdd pair<double, double>
#define SSS \
ios_base::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0);
#define caseT \
int t; \
cin >> t; \
while (t--)
const int N = 2e5 + 10, mod = 1e9 + 7;
const int M = 1e6 + 10;
int h[N], e[M], w[M], ne[M];
int st[N];
int p[N];
bool flag = true;
int idx;
int n, k;
int find(int x)
{
if (p[x] != x)
p[x] = find(p[x]);
return p[x];
}
void merge(int a, int b)
{
if (find(a) != find(b))
{
p[find(a)] = find(b);
}
}
void add(int a, int b, int c) // 邻接表
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u, int fa)
{
if (!flag)
return;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (j == fa)
continue;
merge(j, u);
if (st[j] != -1)
{
if (st[j] == st[u] && w[i] == 0)
{
flag = false;
}
else if (st[j] != st[u] && w[i] == 1)
{
flag = false;
}
}
else
{
if (w[i] == 1)
{
st[j] = st[u];
}
else
{
st[j] = (st[u] + 1) % 2;
}
dfs(j, u);
}
if (!flag)
return;
}
}
void solve()
{
cin >> n >> k;
map<pii, int> pi;
memset(h, -1, (n + 10) * 4); // 问就是懒的写结构体
memset(st, -1, (n + 10) * 4);
memset(e, -1, (n + 10) * 4);
memset(w, -1, (n + 10) * 4);
memset(ne, -1, (n + 10) * 4);
for (int i = 1; i <= n; i++) // 并查集初始化
{
p[i] = i;
}
int a, b;
string c;
while (k--)
{
int x;
cin >> a >> b >> c;
if (c == "imposter")
{
x = 0;
}
else
{
x = 1;
}
// 由于每种组合可能不止一次出现,所以得判断是否与前面的指认冲突
if (pi.count({a, b}))
{
if (pi[{a, b}] != x + 1)
{
flag = false;
}
}
else
{
add(a, b, x);
add(b, a, x);
pi[{a, b}] = x + 1;
pi[{b, a}] = x + 1;
}
}
if (!flag)
{
cout << -1 << endl;
flag = true;
return;
}
int cnt = 0;
map<int, int> mp1, mp2; // mp1为并查集中1的数量,mp2为0的数量
for (int i = 1; i <= n; i++)
{
if (st[i] == -1)
{
st[i] = 1;
dfs(i, -1);
}
if (st[i] == 1)
mp1[find(i)]++;
else
mp2[find(i)]++;
}
int ans = 0;
for (auto i = mp1.begin(); i != mp1.end(); i++)
{
ans += max(i->second, mp2[i->first]); // 每次找到最多的身份相加
}
if (!flag)
{
cout << -1 << endl;
}
else
{
cout << ans << endl;
}
flag = true;
}
signed main()
{
SSS;
caseT
{
solve();
}
return 0;
}