Pro
Sco
预计得分: 100+100+50=250 100 + 100 + 50 = 250
实际得分: 100+10+30=140 100 + 10 + 30 = 140
哇哇哇哇哇
Sol
sum
很简单的一道数学题
虽然有两个求和,但是第二个求和是等比数列的求和
直接公式就可以出了
因为要除法取模,所以逆元就可以了
#include<iostream>
#include<cstdio>
using namespace std;
const int mod = 1e9 + 7;
int n , m;
long long ans;
inline long long qpow(int x , int y) {
if(y == 1)
return x % mod;
long long t = qpow(x , y/2) % mod;
if(y % 2 == 0)
return t * t % mod;
return t * t % mod * x % mod;
}
inline long long inv(int x) {
return qpow(x , mod-2);
}
int main() {
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
scanf("%d%d",&n,&m);
if(m == 1) {
printf("%d",((n*(n+1)%mod)*inv(2))%mod);
return 0;
}
for(int i=2; i<=n; i++)
ans = (ans + ((i*(1-qpow(i,m))%mod)*inv(1-i))%mod) % mod;
printf("%lld",(ans+m)%mod);
return 0;
}
tour
第二题也是非常的水,我也是推出了正解
赛后发现写炸了的原因是我当成单向边处理了
本题做法:贪心+最长路
写一写答案的表达式可以发现
最后的答案就是所有路径和的二倍减去距离1号点最远的距离
可以这么理解:我们假设所有的边都走一遍,但是题目没要求最后要回到出发点
因此可以少走一段距离,根据贪心思想,这段距离越长越好
就可以转化为求树上距离原点最长路问题
这时候可以把树当成图来处理,跑一遍最长路即可。
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
struct Node {
int next , to , len;
};
Node e[2*50005];
struct Que {
int num , len , frm;
Que (int nn , int dd , int from) {
num = nn , len = dd , frm = from;
}
bool operator < (const Que &a) const {
return len < a.len;
}
};
priority_queue<Que>q;
int n , tot , head[50005] , dis[50005] , ans;
inline int mymax(int a , int b) { return a>b?a:b; }
void add(int x , int y , int z) {
tot++;
e[tot].next = head[x];
e[tot].to = y;
e[tot].len = z;
head[x] = tot;
}
int dij(int s) {
int res = 0;
dis[s] = 0;
q.push(Que(s , dis[s] , 0));
while(!q.empty()) {
Que u = q.top();
q.pop();
if(u.len != dis[u.num])
continue;
for(int i=head[u.num]; i; i=e[i].next) {
int v = e[i].to;
if(v == u.frm)
continue;
if(dis[v] < dis[u.num] + e[i].len) {
dis[v] = dis[u.num] + e[i].len;
q.push(Que(v , dis[v] , u.num));
}
}
}
for(int i=1; i<=n; i++)
res = mymax(res , dis[i]);
return res;
}
int main() {
freopen("tour.in","r",stdin);
freopen("tour.out","w",stdout);
scanf("%d",&n);
for(int i=1; i<n; i++) {
int x , y , z;
scanf("%d%d%d",&x,&y,&z);
add(x , y , z);
add(y , x , z);
ans = ans + 2 * z;
}
printf("%d",ans-dij(1));
return 0;
}
lucky
把题目完全读错还30分!
不说错误解法了,说我自己读懂题目后打了50分的解法。
直接搜索就行,搜索每一个位置的数字是几,这里用到容器:集合 set s e t
先一边输入一边把幸运数找出来,打上标记
然后深搜,搜索到的幸运数必须不在集合内才能继续搜索
搜完这一层之后,回溯一下,如果能搜到正好 k k 个元素
答案就加一
#include<iostream>
#include<cstdio>
#include<set>
using namespace std;
set<int>s;
int n , k , num[100005] , ans , flag , vis[100005];
int four , seven;
int check4(int opt , int data) {
int t = 0;
while(data) {
if(data % 10 == 4)
t++;
data = data/10;
}
return t;
}
int check7(int opt , int data) {
int t = 0;
while(data) {
if(data % 10 == 7)
t++;
data = data/10;
}
return t;
}
void dfs(int opt , int cnt) {
if(cnt == k)
ans++;
for(int i=opt+1; i<=n; i++) {
if(vis[i] && s.find(num[i])!=s.end())
continue;
if(vis[i]) {
s.insert(num[i]);
flag = 1;
}
dfs(i , cnt+1);
if(flag)
s.erase(num[i]);
}
}
int main() {
freopen("lucky.in","r",stdin);
freopen("lucky.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1; i<=n; i++) {
scanf("%d",&num[i]);
four = check4(i , num[i]);
seven = check7(i , num[i]);
if((four&&!seven) || (!four&&seven))
vis[i] = 1;
}
dfs(0 , 0);
printf("%d",ans);
return 0;
}