给定三个整数。判断是否成立。
如果,输出Yes
;否则,输出No
。
输出 | |||
---|---|---|---|
Yes |
|||
No |
|||
No |
直接按题意计算即可。
#include <cstdio>
using namespace std;
int main()
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
puts(a * a + b * b < c * c? "Yes": "No");
return 0;
}
给定两个长度为的序列:和。
找到符合如下条件的整数的个数:
输出答案。
2
3 2
7 5
3
可以取。
3
1 5 3
10 7 3
0
没有符合条件。
3
3 2 5
6 9 8
2
我们将的限制条件拆解为:
这时,我们可以进一步简化条件:
从而得到,所以合法的的个数为。
#include <cstdio>
using namespace std;
int main()
{
int n, maxa = 1, minb = 1000;
scanf("%d", &n);
for(int i=0; i<n; i++)
{
int a;
scanf("%d", &a);
if(a > maxa) maxa = a;
}
while(n--)
{
int b;
scanf("%d", &b);
if(b < minb) minb = b;
}
if(maxa > minb) puts("0");
else printf("%d\n", minb - maxa + 1);
return 0;
}
给定长度为且只由大写英文字母组成的字符串。
你要处理个请求。
第个请求中由三个整数和组成:
FLIP
IPFL
)。输出执行所有请求后的。
,如果,;如果,。
2
FLIP
2
2 0 0
1 1 4
LPFI
2
FLIP
6
1 1 3
2 0 0
1 1 2
1 2 3
2 0 0
1 1 4
ILPF
首先,的模拟法肯定行不通,会TLE
。
我们考虑优化。
我们很容易发现,的交换操作肯定是的,但的翻转操作是的,所以需要优化。
我们可以用一个变量记录目前是否已经前后翻转(表示已经翻转,表示没有翻转),这时,操作变为如下:
这种算法的时间复杂度为,可轻松通过此题。
#include <cstdio>
#define maxn 400005
using namespace std;
char s[maxn];
int n;
inline void swap(char& x, char& y) { x ^= y ^= x ^= y; }
inline char& calc(int pos) { return s[pos < n? pos + n: pos - n]; }
int main()
{
scanf("%d%s", &n, s);
int q;
scanf("%d", &q);
bool flipped = false;
while(q--)
{
int t, a, b;
scanf("%d%d%d", &t, &a, &b);
a --, b --;
if(t == 2) flipped = !flipped;
else if(flipped) swap(calc(a), calc(b));
else swap(s[a], s[b]);
}
if(flipped)
for(int i=0; i<n; i++)
swap(s[i], s[n + i]);
puts(s);
return 0;
}
我们有一个有个点和条边的简单无向图,第条边连接着顶点和。
我们要给这个图用三种不同的颜色着色,使得相邻的顶点有不同的颜色。
有多少种合法的着色方法?不一定要使用所有颜色。
输出答案。
3 3
1 2
2 3
3 1
6
我们用R
、G
、B
分别代表三种不同的颜色,则有中不同的着色方法,它们分别是RGB
、RBG
、GRB
、GBR
、BRG
、BGR
。
3 0
27
这个图没有边,所以任意着色都是可行的,一共有种方法。
4 6
1 2
2 3
3 4
2 4
1 3
1 4
0
这里没有合法方案。
20 0
3486784401
我们将图中的每个连通块依次暴力算出所有可能的着色方案数,再相乘即可。
其实,这里我们最大的总尝试数不是,而是,因为使用时每个点的前一个点的颜色已经定好了,只需要尝试两种可能即可。
似乎没人发现可以用unsigned int
吧……
#include <cstdio>
#include <vector>
#define maxn 25
using namespace std;
vector<int> G[maxn];
int col[maxn], dep[maxn];
inline int next(int c) { return (c + 1) % 3; }
int paint(int v)
{
for(int u: G[v])
if(col[v] == col[u])
return 0;
int ans = 1;
for(int u: G[v])
{
if(dep[u] == -1) dep[u] = dep[v] + 1;
if(dep[u] == dep[v] + 1)
{
col[u] = next(col[v]);
int res = paint(u);
col[u] = next(col[u]);
res += paint(u);
col[u] = -1;
if(res == 0) return 0;
ans *= res;
}
}
return ans;
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
while(m--)
{
int x, y;
scanf("%d%d", &x, &y);
G[--x].push_back(--y);
G[y].push_back(x);
}
for(int i=0; i<n; i++)
col[i] = dep[i] = -1;
unsigned int ans = 1;
for(int i=0; i<n; i++)
if(dep[i] == -1)
{
col[i] = dep[i] = 0;
ans *= 3U * paint(i);
}
printf("%u\n", ans);
return 0;
}
求符合如下条件的的排列的个数:
输出一个整数,即符合条件的排列的个数。
3 1
2 2 1
4
四个符合条件的排列分别为:、、、。
5 2
3 3 2
4 4 3
90
18 0
6402373705728000
由于没有限制条件,所有的个排列都可行。这也是本题的最大输出。
首先,还是先排除的暴力算法,这样做的时间复杂度太高了。
我们考虑状压。令表示从中选出子序列(二进制第位是表示不选,表示选)。
则,,动态转移方程为中所有为的位上把变成的中的和,详见代码。
写代码时注意判断合法性,最终答案应为(全选)。
我这里做了一个小优化,即忽略的条件。当然,我们也可以不用优化,但不能不用long long
!!!
#include <cstdio>
#include <vector>
#define maxn 20
using namespace std;
using LL = long long;
vector<pair<int, int>> lim[maxn];
LL dp[1 << maxn];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
while(m--)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
if(z < y) lim[x].emplace_back(y, z);
}
int mx = 1 << n;
dp[0] = 1LL;
for(int st=0; st<mx; st++)
{
vector<int> s;
for(int i=0; i<n; i++)
if(st >> i & 1)
s.push_back(i);
int cnt = __builtin_popcount(st);
bool ok = true;
for(auto [y, z]: lim[cnt])
{
int tot = 0;
for(auto x: s)
if(x < y && ++tot > z)
{
ok = false;
break;
}
if(!ok) break;
}
if(ok) for(int x: s) dp[st] += dp[st ^ (1 << x)];
}
printf("%lld\n", dp[mx - 1]);
return 0;
}