思路:我们直接暴力的去找就行,如果是正数的话,我们直接除到他不是偶数为止,如果是负数的话,我们为了保证总和是最小的,我们不对负数进行操作。
void solve()
{
int n;
cin >> n;
long long ans = 0;
for (int i = 1; i <= n; i++)
{
int x;
cin >> x;
if (x >= 0)
{
while (x % 2 == 0)
x /= 2;
ans += x;
}
else
ans += x;
}
cout << ans << endl;
}
思路:找规律或者二分
首先我们看看找规律,首先我们可以手推出前面的面积,然后我们发现是
然后我们通过观察就是6个为一组,然后前面四个是两两不变的,然后后面两个是不同的,总体是递增的。
int main()
{
int T;
cin >> T;
while (T--)
{
LL n;
cin >> n;
if (n == 2)
{
cout << -1 << "\n";
continue;
}
int h = (6 - n % 6);
LL k;
if (n % 6 == 0)
k = n;
else
k = n + (6 - n % 6);
LL cnt;
cnt = k / 6;
LL start = max((LL)0, (cnt - 1) * 4) + 1;
int yu = n % 6;
if (yu == 1 || yu == 2)
cout << start << "\n";
else if (yu == 3 || yu == 4)
cout << start + 1 << "\n";
else if (yu == 5)
cout << start + 2 << "\n";
else
cout << start + 3 << "\n";
}
return 0;
}
二分:二分的话我们可以假设我们能凑出来的最大的正方形的边长是a,那么比a小的我们一定也可以凑出来,因为a已经是我们可以凑出的最大的所以比a大的一定不可以被凑出来。因此答案具有单调性。
我们考虑二分答案
上图显示了我们一共用了 3 ∗ a n s − 2 ∗ ( n + 1 ) / 2 3 * ans - 2 * (n + 1) / 2 3∗ans−2∗(n+1)/2快木棒,我们只需要二分的时候和n比较一下大小即可。
注:2的情况特判即可。
void solve()
{
int n;
cin >> n;
if (n == 2)
{
cout << -1 << "\n";
return ;
}
auto check = [&](int x)
{
return 3 * x - 2 * ((n + 1) / 2) <= n;
};
int l = (n + 1) / 2, r = n;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid))
l = mid;
else
r = mid - 1;
}
cout << l << "\n";
}
思路:本题我分了四种情况。
第一种n可以被4整除,那么我们发现4个为一组,1和3,2和4相互配对即可。
第二种是是偶数但是不能被4整除的,我们依旧按照4个进行配对即可,但是我们需要调整最后6个的位置。1和4,2和5,3和6配对即可。
然后是奇数减去一可以被4整除的情况,那我们把前n-1个数按照4组进行配对即可,然后我们在更改一下最后三个数的位置1对2,2对3,3对1即可。
最后是是奇数但是(n-1)不能被4整除的情况,此时呢我们调整一下前5个数的顺序,使得前5个数满足条件,之后的数按照情况2把后面的数调整完成即可。
正常的思路是按照n%4,n%5和n%6进行的分类。
#include
using namespace std;
unordered_map<int, int> mp;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int n;
cin >> n;
if (n <= 3 || n == 7)
{
cout << -1 << "\n";
return 0;
}
if (n % 4 == 0)
{
for (int i = 1; i <= n; i += 4)
{
cout << i + 2 << ' ' << i + 3 << ' ' << i << ' ' << i + 1 << ' ';
}
}
else if (n % 2 == 0)
{
int flag = 1;
for (int i = 1; i <= n; i += 2)
{
if (i == n - 1)
{
mp[i] = i - 2;
mp[i + 1] = i - 1;
continue;
}
if (flag % 2 == 1)
{
mp[i] = i + 2;
mp[i + 1] = i + 3;
}
else
{
mp[i] = i - 2;
mp[i + 1] = i - 1;
}
flag++;
}
int start = n - 5;
mp[start] = start + 3;
mp[start + 1] = start + 1 + 3;
mp[start + 2] = start + 2 + 3;
mp[start + 3] = start + 3 - 3;
mp[start + 4] = start + 4 - 3;
mp[start + 5] = start + 5 - 3;
for (int i = 1; i <= n; i++)
cout << mp[i] << ' ';
}
else if (n % 2 == 1)
{
if ((n - 1) % 4 == 0)
{
for (int i = 1; i <= n - 1; i += 4)
{
mp[i] = i + 2;
mp[i + 1] = i + 3;
mp[i + 2] = i;
mp[i + 3] = i + 1;
}
int a = mp[n - 2];
int b = mp[n - 1];
mp[n - 2] = n;
mp[n - 1] = a;
mp[n] = b;
for (int i = 1; i <= n; i++)
cout << mp[i] << ' ';
}
else
{
cout << 3 << ' ' << 4 << ' ' << 5 << ' ' << 1 << ' ' << 2 << ' ';
int flag = 1;
for (int i = 6; i <= n; i += 2)
{
if (i == n - 1)
{
mp[i] = i - 2;
mp[i + 1] = i - 1;
continue;
}
if (flag % 2 == 1)
{
mp[i] = i + 2;
mp[i + 1] = i + 3;
}
else
{
mp[i] = i - 2;
mp[i + 1] = i - 1;
}
flag++;
}
int start = n - 5;
mp[start] = start + 3;
mp[start + 1] = start + 1 + 3;
mp[start + 2] = start + 2 + 3;
mp[start + 3] = start + 3 - 3;
mp[start + 4] = start + 4 - 3;
mp[start + 5] = start + 5 - 3;
for (int i = 6; i <= n; i++)
cout << mp[i] << ' ';
}
}
return 0;
}
思路:赛时直接猜的结论偶数小红胜,奇数小紫胜。
int main()
{
LL n;
cin >> n;
if (n % 2 == 0)
cout << "kou" << "\n";
else
cout << "yukari" << "\n";
return 0;
}
思路:这个题的话我们翻译一下题意就是,能否将给我们的两个点,以给我们两个点的中点为中心旋转90后得到的点x,y均为整数(不存在小数)。
我们可以知道一个点(x,y)按照另一个点(x1,y1)顺时针旋转90度后的坐标是(y-y1+x1,x1-x+y1),然后我们一开始判断一下是否是小数即可。细节见代码。
#include
using namespace std;
typedef long long LL;
int main()
{
LL xa, ya, xb, yb;
cin >> xa >> ya >> xb >> yb;
int h = (xa + ya) % 2;
int k = (xb + yb) % 2;
if ((h && !k) || (!h && k))
{
cout << "No Answer!" << "\n";
return 0;
}
double x = ((double)xa + (double)xb) / 2.0;
double y = ((double)ya + (double)yb) / 2.0;
double ansx = ya - y + x;
double ansy = x - xa + y;
cout << (LL)ansx << ' ' << (LL)ansy << "\n";
return 0;
}
cout<<42;
思路:我们可以dfs出每种情况,然后判断是否可行,可行的话直接输出,不可行的话最后输出-1即可。
注意我们这里的快速幂是有可能爆longlong的,所以我们在对a进行操作的时候要先模上模数
#include
using namespace std;
#define int long long
vector<int> v;
vector<char> ch;
int ans;
int flag;
char d[4] = {' ', '+', '-', '#'};
char a[15];
int n;
int qmi(int a, int k, int p)
{
int res = 1;
a %= p;//要先%p不然会爆longlong
while (k)
{
if (k & 1)
res = res * a % p;
a = a * a % p;
k >>= 1;
}
return res;
}
void dfs(int u, int now)
{
if (u == n)
{
if (now == ans)
{
flag = 1;
for (int i = 0; i < n - 1; i++)
{
cout << v[i] << ch[i];
}
cout << v[n - 1] << '=' << ans << "\n";
exit(0);
}
return ;
}
for (int i = 1; i <= 3; i++)
{
if (i == 3 && ((now <= 0) || (v[u] <= 0)))
continue;
ch.push_back(d[i]);
if (i == 1)
dfs(u + 1, now + v[u]);
if (i == 2)
dfs(u + 1, now - v[u]);
if (i == 3)
dfs(u + 1, qmi(now, now, v[u]));
ch.pop_back();
}
}
void get(string s)
{
int res = 0;
for (int i = 0; i < (int)s.size(); i++)
{
res *= 10;
res += s[i] - '0';
}
v.push_back(res);
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
string s;
cin >> s;
int id = 0;
string ss = "";
for (int i = 0; i < (int)s.size(); i++)
{
if (s[i] == '=' || s[i] == '?')
{
get(ss);
ss = "";
}
else
ss += s[i];
if (s[i] == '=')
{
id = i + 1;
break;
}
}
for (int i = id; i < (int)s.size(); i++)
ss += s[i];
get(ss);
ans = v.back();
v.pop_back();
n = (int)v.size();
dfs(1, v[0]);
if (!flag)
cout << -1 << "\n";
return 0;
}
思路:题目中给了我们三种情况,我们大致可以猜测答案就是按这三总情况来分类。
我们看第一类,给我们的数是偶数n并且n-1是素数,那么素数的约数只有1和它本身,我们发现1+n-1=n这就是我们想要的情况,但是题目中要求等于自身的那个约数不算。那么怎么办呢,我们直接 ( n − 1 ) ∗ ( n − 1 ) (n-1)*(n-1) (n−1)∗(n−1)即可。那么约数只有1,n-1,(n-1)*(n-1)三个,并且最后一个不算。因此这种情况答案就是 ( n − 1 ) ∗ ( n − 1 ) (n-1)*(n-1) (n−1)∗(n−1)
我们看第二类,第二类是给我们一个偶数n并且呢(n-3)是素数。我们发现如果按n-3的情况来看的话我们少了一个约数,这个约数是2,也就是说1+n-3+2=n,那么此时怎么办呢,我们发现直接 2 ∗ ( n − 3 ) 2*(n-3) 2∗(n−3)即可,这样的话,我们会得到1,2,(n-3)和2*(n-3)这四个约数,但是呢最后那一个不算,那么也就正好凑出了我们想要的三个约数。因此答案是 2 ∗ ( n − 3 ) 2*(n-3) 2∗(n−3)
那么最后一种也就是奇数的情况,我们考虑哥德巴赫猜想任意一个大于2的偶数都可以写成两个质数之和,即 p r i m e s 1 + p r i m e s 2 = n ( 偶数 ) primes1+primes2 = n(偶数) primes1+primes2=n(偶数),我们转化一下就是 1 + p r i m e s 1 + p r i m e s 2 = n ( 奇数 ) 1+primes1+primes2 = n(奇数) 1+primes1+primes2=n(奇数)。那我们直接线性筛,筛完之后暴力的一对一对的去找即可。
#include
using namespace std;
#define int long long
const int N = 1e6 + 10;
int primes[N], cnt;
bool st[N];
void get_primes(int n)
{
for (int i = 2; i <= n; i++)
{
if (!st[i])
primes[cnt++] = i;
for (int j = 0; i * primes[j] <= n; j++)
{
st[i * primes[j]] = true;
if (i % primes[j] == 0)
break;
}
}
}
void solve()
{
int n;
cin >> n;
if (n % 2 == 0)
{
if (n == 2)
{
cout << 3 << "\n";
return ;
}
if (st[n - 1] == false)
cout << (n - 1) * (n - 1) << "\n";
else
cout << 2 * (n - 3) << "\n";
return ;
}
else if (n == 1)
{
cout << 2 << "\n";
return ;
}
else if (n == 3)
{
cout << 4 << "\n";
return ;
}
else if (n == 5)
{
cout << -1 << "\n";
return ;
}
else if (n == 7)
{
cout << 8 << "\n";
return ;
}
else
{
for (int i = 2; i <= n; i++)
{
if (!st[i] && !st[n - i - 1])
{
cout << i*(n - i - 1) << "\n";
return ;
}
}
}
cout << -1 << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T;
get_primes(1000000);
cin >> T;
while (T--)
solve();
return 0;
}
思路:首先呢,我们分析一下样例,可以猜测我们按顺序放置质因子是最大值。然后我们通过约数定理可以知道,约数个数等于全部质因子的(指数+1)的乘积。我们现在以样例为例子。 2 , 3 , 7 , 2 , 3 , 3 2, 3, 7, 2, 3, 3 2,3,7,2,3,3对于前三个数来说呢,因为2和3和7都出现了一次,那么对于前三个数来说约数个数依次是 ( 1 + 1 ) = 2 (1+1)=2 (1+1)=2, ( 1 + 1 ) ∗ ( 1 + 1 ) = 4 (1+1)*(1+1)=4 (1+1)∗(1+1)=4, ( 1 + 1 ) ∗ ( 1 + 1 ) ∗ ( 1 + 1 ) = 8 (1+1)*(1+1)*(1+1)=8 (1+1)∗(1+1)∗(1+1)=8,然后把 2 , 3 2,3 2,3看做一组,此时2和3均出现了两次,那么约数依次就是 ( 1 + 1 + 1 ) ∗ ( 1 + 1 ) ∗ ( 1 + 1 ) = 12 (1+1+1)*(1+1)*(1+1)=12 (1+1+1)∗(1+1)∗(1+1)=12, ( 1 + 1 + 1 ) ∗ ( 1 + 1 + 1 ) ∗ ( 1 + 1 ) = 18 (1+1+1)*(1+1+1)*(1+1)=18 (1+1+1)∗(1+1+1)∗(1+1)=18,最后的3是一组约数是 ( 1 + 1 + 1 + 1 ) ∗ ( 1 + 1 + 1 ) ∗ ( 1 + 1 ) = 24 (1+1+1+1)*(1+1+1)*(1+1)=24 (1+1+1+1)∗(1+1+1)∗(1+1)=24整个的和就是68.
然后我们可以发现每段之间都是一个等比数列段的公比是 ( i + 1 ) / i (i+1)/i (i+1)/i,我们可以利用差分数组c来存,c[i]为出现次数大于等于i的数的质因子的个数。那么我们分段的时候一段就是对应的c[i]个数。我们可以利用等比数列的求和公式来求解一段的和,然后整体加起来就是整个的答案。
求每一段的首项的话,我们可以用前一段的末项。(具体详见代码)
因为此题的话要求我们在模数下求,所以我们要用到的逆元。
#include
using namespace std;
#define int long long
const int N = 2e5 + 10, mod = 1e9 + 7;
int a[N], n;
int c[N];
int qmi(int a, int k, int p)
{
int res = 1;
while (k)
{
if (k & 1)
res = res * a % p;
a = a * a % p;
k >>= 1;
}
return res;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
c[1]++;
c[a[i] + 1]--;
}
for (int i = 1; i <= 200005; i++) c[i] = c[i] + c[i - 1];
int ans = 0, start = 2, en = 1;
for (int i = 1; i <= 200005; i++)
{
if (!c[i])
break;
int q = (i + 1) * qmi(i, mod - 2, mod) % mod;
en = start * max((long long)1, qmi(q, c[i] - 1, mod)) % mod;
int a = (qmi(q, c[i], mod) - 1) % mod;
int b = (q - 1) % mod;
int g = a * qmi(b, mod - 2, mod) % mod;
ans += start * g % mod;
start = (en * qmi(i + 1, mod - 2, mod) % mod) * (i + 2) % mod;
}
cout << ans % mod << "\n";
return 0;
}