12点四十起床饭都没恰,温州阴郁的天气隐隐暗示了今天的基调
https://ac.nowcoder.com/acm/contest/3003#question
A.做游戏
石头剪刀布wa两发娱乐一下,int的read加起来的时候在右边炸了一回,重新写sclll没抄对,甚至样例都没过就直接上了,这脑残的行径能怪谁呢
#include <cstdio> #include <cmath> #include <algorithm> #include <iostream> #include <cstring> #include <queue> #include <set> #include <map> #include <stack> using namespace std; #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scl(a) scanf("%lld",&a) #define scll(a,b) scanf("%lld%lld",&a,&b) #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c) #define prl(a) printf("%lld ",a) #define prd(a) printf("%d ",a) #define prf(a) printf("%lf ",a) #define ptd(a) printf("%d ",a) #define scf(a) scanf("%lf",&a) #define scff(a,b) scanf("%lf%lf",&a,&b) #define scfff(a,b,c) scanf("%lf%lf%lf",&a,&b,&c) #define rint register int #define mem(a) memset(a,0,sizeof(a)) #define rush() int T;scd(T);while(T--) #define lc(i) (i<<1) #define rc(i) (i<<1|1) #define mp make_pair #define lowbit(x) (x&(-x)) typedef long long ll; typedef double db; inline int read() {char c=getchar();int x=0,f=1;while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}return x*f;} int main () { ll a,b,c,x,y,z; sclll(a,b,c); sclll(x,y,z); ll ans = 0; ans = min(a,y) + min(b,z) + min(c,x); prl(ans); return 0; }
B.排数字
题意:一个可以重排的字符串,重排的子串可能包含616的最大个数
思路:贪心地6161616个数连续两个6可以贡献1,1可以贡献为1,取最小值
#include <cstdio> #include <cmath> #include <algorithm> #include <iostream> #include <cstring> #include <queue> #include <set> #include <map> #include <stack> using namespace std; #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scl(a) scanf("%lld",&a) #define scll(a,b) scanf("%lld%lld",&a,&b) #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c) #define prl(a) printf("%lld ",a) #define prd(a) printf("%d ",a) #define prf(a) printf("%lf ",a) #define ptd(a) printf("%d ",a) #define scf(a) scanf("%lf",&a) #define scff(a,b) scanf("%lf%lf",&a,&b) #define scfff(a,b,c) scanf("%lf%lf%lf",&a,&b,&c) #define rint register int #define mem(a) memset(a,0,sizeof(a)) #define rush() int T;scd(T);while(T--) #define lc(i) (i<<1) #define rc(i) (i<<1|1) #define mp make_pair #define lowbit(x) (x&(-x)) typedef long long ll; typedef double db; inline int read() {char c=getchar();int x=0,f=1;while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}return x*f;} const int maxn = 2e5 + 10; char s[maxn]; int main () { int n = read(); scanf("%s",s + 1); int c1 = 0, c6 = 0; for (int i = 1; i <= n; ++i) { if (s[i] - '0' == 1) c1++; else if (s[i] - '0' == 6)c6++; } prd(min(c6-1,c1)); return 0; }
C.算概率
题意:概率a/b%(1e9 + 7) == p, 即p满足 p*b%(1e9 + 7) = a, pi就可以代表第i个题目正确的概率,问考生正确各题的概率为多少。
思路:错误的概率(1-a/b)=(b-a)/b,对其%(1e9 + 7),设答案为q,q*b%(1e9 + 7) = b-a,那么加上上面 p*b%(1e9 + 7) = a,(q + p)*b%(1e9 + 7) = b,所以可以得到(q + p) % (1e9 + 7) == 1,则q = 1-p+(1e9 + 7),至于两概率之乘积%(1e9 + 7)和两概率对应的 p 值是相等的也好证明,
要证(a1 * a2)/(b1 * b2) % (1e9 + 7) == p1*p2
只需证(b1 * b2) * (p1 * p2) % (1e9 + 7) == a1 * a2
等价于(b1 * p1) * (b2 * p2) % (1e9 + 7) == a1 * a2
等价于(b1 * p1) * (b2 * p2) % (1e9 + 7) == (b1 * p1) % (1e9 + 7) * (b2 * p2) % (1e9 + 7) = a1 * a2
以上是yy的证明过程,实际上我并没有做出来这道DP,想得有点偏,但是队友做出来了,那就厚颜无耻地贴过来了,dp[x][y],代表做了x道题,其中对了y道,那么做新的题目的时候,其结果要么是正确的要么是错误的,方程在这了 dp[x][y] = dp[x-1][y-1]*a[i] + dp[x-1][y] * (1e9 + 7 + 1 - a[i]);
#include <cstdio> #include <cmath> #include <algorithm> #include <iostream> #include <cstring> #include <queue> #include <set> #include <map> #include <stack> using namespace std; #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scl(a) scanf("%lld",&a) #define scll(a,b) scanf("%lld%lld",&a,&b) #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c) #define prl(a) printf("%lld ",a) #define prd(a) printf("%d ",a) #define prf(a) printf("%lf ",a) #define ptd(a) printf("%d ",a) #define scf(a) scanf("%lf",&a) #define scff(a,b) scanf("%lf%lf",&a,&b) #define scfff(a,b,c) scanf("%lf%lf%lf",&a,&b,&c) #define rint register int #define mem(a) memset(a,0,sizeof(a)) #define rush() int T;scd(T);while(T--) #define lc(i) (i<<1) #define rc(i) (i<<1|1) #define mp make_pair #define lowbit(x) (x&(-x)) typedef long long ll; typedef double db; inline int read() {char c=getchar();int x=0,f=1;while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}return x*f;} const int maxn = 2e3 + 10; const ll mod = 1e9 + 7; int n; ll a[maxn]; ll dp[maxn][maxn]; int main () { n = read(); for (int i = 1; i<=n; ++i) scl(a[i]); dp[1][0] = mod + 1 - a[1]; for (int i = 2; i<=n; ++i) dp[i][0] = dp[i-1][0] * (mod + 1 - a[i]) % mod; dp[1][1] = a[1]; for (int i = 2; i<=n; ++i) { for (int j = 1; j<=i; ++j) { dp[i][j] = (dp[i-1][j-1]*a[i]%mod + dp[i-1][j]*(mod + 1 - a[i])%mod)%mod; } } for (int i = 0; i<=n; ++i) { printf("%lld ",dp[n][i]%mod); }puts(""); return 0; }
D.数三角
题意:在一个平面上给最多500个点,问其中能组成钝角三角形的个数
思路:觉得吧应该有很多种做法,下午是先确定了底边,再确定另外一个顶点是否能跟底边组成钝角三角形(余弦定理),当然三角形的前提是三点不共线(行列式),行列式想了半天,线代忘记得差不多了...详细做法代码里有
#include <cstdio> #include <cmath> #include <algorithm> #include <iostream> #include <cstring> #include <queue> #include <set> #include <map> #include <stack> using namespace std; #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scl(a) scanf("%lld",&a) #define scll(a,b) scanf("%lld%lld",&a,&b) #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c) #define prl(a) printf("%lld ",a) #define prd(a) printf("%d ",a) #define prf(a) printf("%lf ",a) #define ptd(a) printf("%d ",a) #define scf(a) scanf("%lf",&a) #define scff(a,b) scanf("%lf%lf",&a,&b) #define scfff(a,b,c) scanf("%lf%lf%lf",&a,&b,&c) #define rint register int #define mem(a) memset(a,0,sizeof(a)) #define rush() int T;scd(T);while(T--) #define lc(i) (i<<1) #define rc(i) (i<<1|1) #define mp make_pair #define lowbit(x) (x&(-x)) typedef long long ll; typedef double db; inline int read() {char c=getchar();int x=0,f=1;while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}return x*f;} const int maxn = 2e5 + 10; struct node { ll x, y; }p[550]; int n; ll line(node a, node b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * ((a.y - b.y)); } ll check(int A, int B, int C) { ll a =line(p[B],p[C]); ll b =line(p[A],p[C]); ll c =line(p[B],p[A]); return a + b - c; } ll hanglieshi(int i, int j, int k) { ll x1 = p[i].x - p[j].x; ll y1 = p[i].y - p[j].y; ll x2 = p[i].x - p[k].x; ll y2 = p[i].y - p[k].y; return x1 * y2 - x2 * y1; } int main () { n = read(); for (int i = 1; i <= n; ++i) { scll(p[i].x, p[i].y); } ll ans = 0; for (int i = 1; i <= n; ++i) { for (int j = i + 1; j <= n; ++j) {//确定两个点并且不会重复对底边计数 for (int k = 1; k <= n; ++k) { if (k == j || k == i) continue; if (check(i,j,k) < 0 && hanglieshi(i,j,k) != 0) {//前面通过勾股定理的变形或者说是余弦定理的变形后面是通过行列式确定三点不共线 ans++; } } } } prl(ans); return 0; }
E.做计数
题意:满足i*j<=n的i和j,能够满足根号i+根号j=根号k,k是任意正整数
思路:暴力肯定会T,for i for j 判断, 直接O(n2)暴毙,打个表或者是看得出来就会发现,答案只跟完全平方数有关,然后想到每添加一个完全平方数,通过分析,对答案的贡献数为完全平方数的因子数,这样就把答案变成了O(n)
#include <cstdio> #include <cmath> #include <algorithm> #include <iostream> #include <cstring> #include <queue> #include <set> #include <map> #include <stack> using namespace std; #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scl(a) scanf("%lld",&a) #define scll(a,b) scanf("%lld%lld",&a,&b) #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c) #define prl(a) printf("%lld ",a) #define prd(a) printf("%d ",a) #define prf(a) printf("%lf ",a) #define ptd(a) printf("%d ",a) #define scf(a) scanf("%lf",&a) #define scff(a,b) scanf("%lf%lf",&a,&b) #define scfff(a,b,c) scanf("%lf%lf%lf",&a,&b,&c) #define rint register int #define mem(a) memset(a,0,sizeof(a)) #define rush() int T;scd(T);while(T--) #define lc(i) (i<<1) #define rc(i) (i<<1|1) #define mp make_pair #define lowbit(x) (x&(-x)) typedef long long ll; typedef double db; inline int read() {char c=getchar();int x=0,f=1;while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}return x*f;} const int maxn = 2e5 + 10; ll solve(ll x) { set<ll>se; for (ll i = 1; i * i <= x; ++i) { if (x % i==0)se.insert(i),se.insert(x/i); } return se.size(); } int main () { const ll lim = 4e7; ll i = 1; ll n = i; scl(n); ll ans = 0; for (ll i = 1; i * i <= n; ++i) { ans += solve(i * i); } prl(ans); return 0; }
F.拿物品
题意:一个物品有两个属性,分别只对两个玩家有效
思路:假设原本两个玩家都可以拿得到所有物品,一个玩家拿走一个物品就相当于把一个物品对自己有利的属性加起来,并且使对对方有利的属性无法获得
#include <cstdio> #include <cmath> #include <algorithm> #include <iostream> #include <cstring> #include <queue> #include <set> #include <map> #include <stack> using namespace std; #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scl(a) scanf("%lld",&a) #define scll(a,b) scanf("%lld%lld",&a,&b) #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c) #define prl(a) printf("%lld ",a) #define prd(a) printf("%d ",a) #define prf(a) printf("%lf ",a) #define ptd(a) printf("%d ",a) #define scf(a) scanf("%lf",&a) #define scff(a,b) scanf("%lf%lf",&a,&b) #define scfff(a,b,c) scanf("%lf%lf%lf",&a,&b,&c) #define rint register int #define mem(a) memset(a,0,sizeof(a)) #define rush() int T;scd(T);while(T--) #define lc(i) (i<<1) #define rc(i) (i<<1|1) #define mp make_pair #define lowbit(x) (x&(-x)) typedef long long ll; typedef double db; inline int read() {char c=getchar();int x=0,f=1;while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}return x*f;} const int maxn = 2e5 + 10; struct node { ll a, b, id, sum; }p[maxn]; bool cmp(node a, node b){ return a.sum > b.sum; } ll ans1[maxn],ans2[maxn],tot1,tot2; int main () { int n; scd(n); for (int i = 1; i<=n; ++i) scl(p[i].a); for (int i = 1; i<=n; ++i) scl(p[i].b); for (int i = 1; i<=n; ++i) p[i].id = i; for (int i = 1; i<=n; ++i) p[i].sum = p[i].a + p[i].b; sort(p+1,p+1+n,cmp); tot1 = tot2 = 0; for (int i = 1; i<=n; ++i){ if(i&1){ ans1[++tot1] = p[i].id; } else ans2[++tot2] = p[i].id; } for (int i = 1; i <= tot1; ++i) printf("%lld%c", ans1[i],i==tot1?' ':' '); for (int i = 1; i <= tot2; ++i) printf("%lld%c", ans2[i],i==tot2?' ':' '); return 0; }
G.判正误
对大佬们来说显然是easy,什么hash啥的,又是魔幻操作,意想不到的是pow居然可以直接过,编译器果然是博大精深,法力无边。
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll a,b,c,d,e,f,g; const ll mod = 1e9 + 7; ll qpow(ll a, ll b){ ll r = 1; while (b) { if (b&1) { r = (r * a) % mod; } b>>=1; a = (a * a) %mod; } return r; } int main(){ int t;scanf("%d",&t); while (t--){ scanf("%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e,&f,&g); ll aa = qpow(a,d); ll bb = qpow(b,e); ll cc = qpow(c,f); g = g % mod; if (aa + bb + cc == g % mod) { puts("Yes"); } else puts("No"); } return 0; }
H.施魔法
看了题解,结论是,去学一手划分dp
题意:给个数组可以将其划分成很多块,每一块至少要k个元素,问每一块的极差之和最小是多少
思路:先进行排序,然后一个个元素进行分配,设dp[x]为分配到第x个元素的极差之和
直接给方程dp[i] = min(dp[i-1]-a[i-1]+a[i], dp[i-k]+a[i]-a[i-k+1]);
要知道最优解肯定是sort以后在数组里是一段段的,括号里前半部分的是把当前元素当成是末端,原本dp[i-1]肯定是以a[i-1]为结尾的,现在变成了a[i]结尾,所以先减去a[i-1]再加上a[i]
括号后半部分则考虑直接开一个新的区间,这个区间长度至少是k,所以是从i-k+1到i
#include <cstdio> #include <cmath> #include <algorithm> #include <iostream> #include <cstring> #include <queue> #include <set> #include <map> #include <stack> using namespace std; #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scl(a) scanf("%lld",&a) #define scll(a,b) scanf("%lld%lld",&a,&b) #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c) #define prl(a) printf("%lld ",a) #define prd(a) printf("%d ",a) #define prf(a) printf("%lf ",a) #define ptd(a) printf("%d ",a) #define scf(a) scanf("%lf",&a) #define scff(a,b) scanf("%lf%lf",&a,&b) #define scfff(a,b,c) scanf("%lf%lf%lf",&a,&b,&c) #define rint register int #define mem(a) memset(a,0,sizeof(a)) #define rush() int T;scd(T);while(T--) #define lc(i) (i<<1) #define rc(i) (i<<1|1) #define mp make_pair #define lowbit(x) (x&(-x)) typedef long long ll; typedef double db; inline int read() {char c=getchar();int x=0,f=1;while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}return x*f;} const int maxn = 3e5 + 10; const int inf = 0x3f3f3f3f; const ll mod = 1e9 + 7; int n, k; int a[maxn], dp[maxn]; int main(){ scdd(n, k); for (int i = 1; i <= n; ++i) a[i] = read(); sort(a + 1, a + 1 + n); for (int i = 0; i <= n; ++i) dp[i] = inf; dp[k] = a[k] - a[1]; for (int i = k+1; i <= n; ++i) { dp[i] = min(dp[i-1]-a[i-1]+a[i], dp[i-k]+a[i]-a[i-k+1]); } prd(dp[n]); return 0; }
I.建通道
题意:n个星球有权重v[i],要使他们全都连通,连接两个星球之间的费用是lowbit(v[i] ^ v[j])
思路:大佬的思路是,首先相同权重的星球的异或值为0,直接相连了。然后如果权重中有奇数或者偶数,就直接把偶数跟奇数相互连接,这时费用就是0,但是显然不可能有这么好的事情发生,所以如果都是奇数或者是偶数的情况,考虑的位数+1,进行重复性的判断。
#include <cstdio> #include <cmath> #include <algorithm> #include <iostream> #include <cstring> #include <queue> #include <set> #include <map> #include <stack> using namespace std; #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scl(a) scanf("%lld",&a) #define scll(a,b) scanf("%lld%lld",&a,&b) #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c) #define prl(a) printf("%lld ",a) #define prd(a) printf("%d ",a) #define prf(a) printf("%lf ",a) #define ptd(a) printf("%d ",a) #define scf(a) scanf("%lf",&a) #define scff(a,b) scanf("%lf%lf",&a,&b) #define scfff(a,b,c) scanf("%lf%lf%lf",&a,&b,&c) #define rint register int #define mem(a) memset(a,0,sizeof(a)) #define rush() int T;scd(T);while(T--) #define lc(i) (i<<1) #define rc(i) (i<<1|1) #define mp make_pair #define lowbit(x) (x&(-x)) typedef long long ll; typedef double db; inline int read() {char c=getchar();int x=0,f=1;while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}return x*f;} const int maxn = 2e5 + 10; const int inf = 0x3f3f3f3f; const ll mod = 1e9 + 7; int v[maxn]; int main(){ int n = read(); for (int i = 1; i <= n; ++i) v[i] = read(); sort(v+1,v+1+n); n = unique(v+1, v+1+n) - v-1; for (int i = 0; i < 30; ++i) { ll k = 1 << i; int a = 0, b = 0; for (int j = 1; j <= n; ++j) if (v[j]&k)a++; else b++; if (a > 0 && b > 0) { prl(k * (n - 1)); return 0; } } prd(0); return 0; }
J求函数
线段树维护矩阵,先看了网上有几篇右乘的,本来想着左乘也应该是一个道理,从矩阵上看应该就是他们的转置矩阵,结果居然在矩阵快速幂里卡死,原来是要对数据mod,然而并没有看到题目最后的取模
,,,
#include <cstdio> #include <cmath> #include <algorithm> #include <iostream> #include <cstring> #include <queue> #include <set> #include <map> #include <stack> using namespace std; #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scl(a) scanf("%lld",&a) #define scll(a,b) scanf("%lld%lld",&a,&b) #define prl(a) printf("%lld ",a) #define prd(a) printf("%d ",a) #define prf(a) printf("%lf ",a) #define ptd(a) printf("%d ",a) #define scf(a) scanf("%lf",&a) #define scff(a,b) scanf("%lf%lf",&a,&b) #define scfff(a,b,c) scanf("%lf%lf%lf",&a,&b,&c) #define rint register int #define mem(a) memset(a,0,sizeof(a)) #define rush() int T;scd(T);while(T--) #define lc(i) (i<<1) #define rc(i) (i<<1|1) #define mp make_pair typedef long long ll; typedef double db; inline int read() {char c=getchar();int x=0,f=1;while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}return x*f;} const int maxn = 2e5 + 10; const int mod = 1e9 + 7; ll k[maxn], b[maxn]; struct Mat{ ll data[2][2]; Mat(int type = 0) { for (int i = 0; i < 2; ++i)for (int j = 0; j < 2; ++j)data[i][j] = 0; if (type == 1){ for (int i = 0; i < 2; ++i) data[i][i] = 1; } } Mat operator*(const Mat h) { Mat res; for (int i = 0; i < 2; ++i) { for (int j = 0; j < 2; ++j) { for (int k = 0; k < 2; ++k) { res.data[i][j] += this->data[i][k] * h.data[k][j]; res.data[i][j] %= mod; } } } return res; } }; Mat tree[maxn<<2]; void pushup(int i) { tree[i] = tree[rc(i)] * tree[lc(i)]; } void update(int i, int l, int r, int pos) { if (l == r) { tree[i].data[0][0] = k[l];tree[i].data[0][1] = b[l]; tree[i].data[1][0] = 0; tree[i].data[1][1] = 1; return; } int mid = (l + r) >> 1; if (pos <= mid) update(lc(i),l,mid,pos); else update(rc(i),mid+1,r,pos); pushup(i); } Mat query(int i, int l, int r, int L, int R) { if (L <= l && r <= R) return tree[i]; Mat res(1); int mid = (l + r)>>1; if ( L<=mid ) res = query(lc(i), l, mid, L, R) * res; if ( R>mid ) res = query(rc(i), mid + 1, r, L, R) * res; return res; } int main() { int n = read(), m = read(); for (int i = 1; i <= n; ++i) scl(k[i]); for (int i = 1; i <= n; ++i) scl(b[i]); for (int i = 1; i <= n; ++i) update(1, 1, n, i); while (m--) { int t = read(); if (t == 1) { int p = read(); scll(k[p], b[p]); update(1, 1, n, p); } else { int l = read(), r = read(); Mat res; res.data[0][0] = res.data[1][0] = 1; res = query(1, 1, n, l, r) * res; prl(res.data[0][0]); } } return 0; }