晚上的一场cf,继续上不了紫,生受打击,故直接补满一套。
C:
题面链接: http://codeforces.com/contest/1230/problem/C
有21种dominoes,每种dominoes由两部分构成,每个部分是一个1-6的数,故共有21种dominoes 题意给定一个图每个边你可以放一个dominoes两个部分分别对着一个点但是每个点只能被一种数字对着。n<=7 , m <= n*(n-1)/2
思路:暴力出每个点被哪个数字对着然后求出最多用几个dominoes
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
P edge[1005];
vector<int> G[10];
int n,m;
int t[10];
int vis[10];
int used[105][105];
int ans;
void f(){
int now = 0;
for(int i=0;i<m;i++){
int u = t[edge[i].first];
int v = t[edge[i].second];
if(u>v)swap(u,v);
if(!used[u][v]){
now ++;
used[u][v] = 1;
}
}
ans = max(ans,now);
for(int i=0;i<m;i++){
int u = t[edge[i].first];
int v = t[edge[i].second];
if(u>v)swap(u,v);
used[u][v] = 0;
}
}
void dfs(int v){
if(v==n+1){
f();
return;
}
int maxv = 6;
for(int i=1;i<=maxv;i++){
t[v] = i;
dfs(v+1);
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++){
int u,v;
scanf("%d%d",&u,&v);
edge[i] = P(u,v);
}
dfs(1);
cout << ans;
return 0;
}
D:
题面链接:http://codeforces.com/contest/1230/problem/D
题意:n个学生 每个人会若干钟算法(<60)并且有一个能力值。一个学生只要会一个或以上的别人不会的算法就认为自己比别人强,要求选出最大的能力值总和,并且这些人没有人认为自己比所有人强。
思路:至少有两个会的算法一模一样的否则最大的那个人肯定认为自己比所有人强。把所有有相同算法的人都拿出来。然后再找属于这些的子集的人。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
P a[7007];
int used[7007];
ll sum;
int cnt[100];
vector<ll> v;
int vis[65];
int check(ll num){
int n = v.size();
memset(vis,0,sizeof(vis));
ll tmp = num;
int now =0 ;
while(tmp){
if(tmp%2){
vis[now] = 1;
}
tmp /= 2;
now ++;
}
for(int i=0;i<n;i++){
if(v[i] < num) return 0;
int ok = 1;
tmp = v[i];
now = 0;
while(tmp){
if(vis[now] && tmp%2==0){
ok = 0;
break;
}
tmp /= 2;
now ++;
}
if(ok) return 1;
}
return 0;
}
int main()
{
int n;
cin >> n;
for(int i=0;i<n;i++){
scanf("%lld",&a[i].first);
}
for(int i=0;i<n;i++){
scanf("%lld",&a[i].second);
}
sort(a,a+n);
reverse(a,a+n);
int sz = 0;
for(int i=0;i < n - 1;i++){
if(a[i].first == a[i+1].first){
if(!used[i]){
used[i] = 1;
sum += a[i].second;
sz++;
}
if(!used[i+1]){
used[i+1] = 1;
sum += a[i+1].second;
sz++;
}
v.push_back(a[i].first);
}
}
for(int i=0;i<n;i++){
if(used[i]) continue;
if(check(a[i].first)){
sum += a[i].second;
sz ++;
}
}
if(sz<2)printf("0\n");
else cout << sum ;
return 0;
}
E:
题面链接:http://codeforces.com/contest/1230/problem/E
题意:给定一个树,每个点有一个权值(<1e12)要求求出 所有f(u,v) --u is an ancestor of v,f(u,v) u到v路径上的gcd
思路:用到一个知识:一条路径上不同的gcd很少一般小于100,故直接暴力。知道这个就是水体了。用map处理一下,注意要从根往叶子算,从小到上递归的话会TLE常数过大。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef pair<ll,ll> P;
int mod = (int)1e9 + 7;
ll a[100050];
vector<int> G[100050];
map<ll,int> dp[100050];
ll gcd(ll x,ll y){
if(!y) return x;
return gcd(y,x%y);
}
ll ans;
void dfs(int v,int fa){
for(auto div:dp[fa]){
int num = div.second;
ll now = gcd(div.first , a[v]);
dp[v][now] += num;
ans += 1ll * num * now;
if(ans >= mod) ans %= mod;
}
//dp[fa].clear();
ans = (ans + a[v])%mod;
dp[v][a[v]]++;
for(auto to:G[v]){
if(to == fa) continue;
dfs(to,v);
}
}
int main()
{
int n;
cin >> n;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int i=0;i<n-1;i++){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0);
cout << ans;
return 0;
}
F:
题面链接:http://codeforces.com/contest/1230/problem/F
题意:n个人(1-n)每个人一开始有i的工资 有q天 每天一个人的工资会变成当前最大。有m个关系u,v两个人相互讨厌 问有多少中bad triple (a讨厌b 且a工资高于b , b讨厌c 且b的工资高于c) 输出q+1,变化前和q天内每次变化后的结果
思路:枚举每个人 是b的身份时给出的贡献 答案就是和自己连边的人中比自己工资高的人的和比自己低的人。q天中每次变化。枚举和他连边的人中算一次变化。维护一个G表示比自己工资少并且讨厌的人的编号。读完提直接两发ac。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
vector<int> G[100050];
ll cnt[100050];
ll xiao[100050];
P edge[100060];
int main()
{
int n , m;
cin >> n >> m;
for(int i = 0 ;i < m; i ++){
int u,v;
scanf("%d%d",&u,&v);
edge[i] = P(u,v);
if(u < v){
G[u].push_back(v);
xiao[v]++;
}
else{
G[v].push_back(u);
xiao[u]++;
}
cnt[v]++;
cnt[u]++;
}
ll ans = 0;
for(int i=1;i<=n;i++){
ans += (cnt[i] - xiao[i]) * xiao[i];
}
cout << ans<< "\n";
int q;
cin >> q;
while(q--){
int id;
scanf("%d",&id);
for(auto to : G[id]){
ans = ans - (cnt[to] - xiao[to]) * xiao[to] + (cnt[to]-xiao[to]+1)*(xiao[to]-1);
G[to].push_back(id);
xiao[to]--;
}
G[id].clear();
ans = ans - (cnt[id]-xiao[id])*xiao[id];
xiao[id] = cnt[id];
printf("%lld\n",ans);
}
return 0;
}