昨天太累了 - - cf 也没打好 头疼 今早重现做了一遍
1-28 组队训练
B题 dp
题意有点冗杂,思索了很久感觉没法贪心,应该是个dp ,但是对于第一关和第二关的经验限制又想不到好的对策。如果我们以第一关经验为0 出发,就算可以取到最优的策略,但是对第二关是有影响的。而且每个怪物分不同关打的时候可以获得不同的exp以及花费不同的time 那么 问题就在于确定这个怪在第几关打最优 。
分析:
大概确定了要枚举第i个怪物,然后由于要先满足第一关后满足第二关,那么就是套个枚举第一关的经验值exp1 和第二关的经验值exp2
那么此时转移方程就很显然了
经验值我们要从大到小枚举,此外,为了线性的转移上去,对怪物的第一关的获得的经验sort一下就OK
ll dp[600][600];
struct pe{
ll v1,t1,v2,t2;
}boss[1111];
bool cmp(pe x,pe y){
return x.v1<y.v1;
}
signed main(){
ll n,s1,s2;
read(n);
read(s1);
read(s2);
for(int i=1;i<=n;i++){
read(boss[i].v1);
read(boss[i].t1);
read(boss[i].v2);
read(boss[i].t2);
}
sort(boss+1,boss+1+n,cmp);
ll inf=1e12;
for(int i=0;i<=s1;i++){
for(int j=0;j<=s2;j++){
dp[i][j]=inf;
}
}
dp[0][0]=0;
for(int i=1;i<=n;i++){
for(int j=s1;j>=0;j--){
for(int k=s2;k>=0;k--){
if(dp[j][k]>=inf){
continue;}
if(j<s1){
// 第一关的经验不够
ll now_s1=j+boss[i].v1;
ll now_s2=k;
if(now_s1>s1){
// 溢出
now_s2=min(s2,now_s2+(now_s1-s1));// 获得溢出经验
now_s1=s1;
}
dp[now_s1][now_s2]=min(dp[now_s1][now_s2],dp[j][k]+boss[i].t1);
}
if(k<s2){
ll now_s1=j;
ll now_s2=min(k+boss[i].v2,s2);
dp[now_s1][now_s2]=min(dp[now_s1][now_s2],dp[j][k]+boss[i].t2);
}
}
}
}
if(dp[s1][s2]>=inf){
printf("-1");
return 0;
}
printf("%lld",dp[s1][s2]);
}
D题 字符串构造,思维模拟
给了我们一个字符串,问能不能重新组合一下,使得该字符串不存在任何相同的长度为n的子串 (字符串长度2n) 字符串围成一个圈
分析:
先记录一下每个字母的数量来观察一下 如果存在一个字符的数量>=2 * n -1 是一定不可以的 再来分析 一个字母出现了2n - 2次 aabb
另外剩下的两个字母是相同的,但是它却是yes 再来分析一下,如果最多的字母的数量小于等于n 那么在一个环里面,他就一定是合法的 可以直接输出该字符串。 另外的就是处理这种2 * n -2 个相同字符的情况了,剔除了n=2, 不难发现剩下的 n 的取值 如果剩下的两个字母是相同的,那么一定无解。
下面来讨论一种针对2*n-2 的构造方法, 如果先拿出来 n 个字符 放一个数量为1的字符,剩下的再放最多的字符,再放最后一个字符 (思索) 妙
#include<bits/stdc++.h>
#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll long long
#define int long long
#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
ll gcd(ll a,ll b){
if(a<0)a=-a;if(b<0)b=-b;return b==0?a:gcd(b,a%b);}
template<typename T>void read(T &res){
bool flag=false;char ch;while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
for(res=ch-48;isdigit(ch=getchar());res=(res<<1)+(res<<3)+ch - 48);flag&&(res=-res);}
ll lcm(ll a,ll b){
return a*b/gcd(a,b);}
ll qp(ll a,ll b,ll mod){
ll ans=1;if(b==0){
return ans%mod;}while(b){
if(b%2==1){
b--;ans=ans*a%mod;}a=a*a%mod;b=b/2;}return ans%mod;}//快速幂%
ll qpn(ll a,ll b, ll p){
ll ans = 1;a%=p;while(b){
if(b&1){
ans = (ans*a)%p;--b;}a =(a*a)%p;b >>= 1;}return ans%p;}//逆元 (分子*qp(分母,mod-2,mod))%mod;
char s[1111111];
ll vis[30];
signed main(){
scanf("%s",s+1);
ll n=strlen(s+1);
ll ma=0;
for(int i=1;i<=n;i++){
ll pos=s[i]-'a'+1;
vis[pos]++;
ma=max(ma,vis[pos]);
}
n=n/2;
if(ma<=n){
printf("YES\n");
for(char i='a';i<='z';i++){
ll op=vis[i-'a'+1];
for(int j=1;j<=op;j++){
printf("%c",i);
}
}
return 0;
}
if(ma>=2*n-1){
printf("NO");
return 0;
}
if(ma==2*n-2){
ll pos=0;
for(char i='a';i<='z';i++){
if(vis[i-'a'+1]==2){
printf("NO");
return 0;
}
if(vis[i-'a'+1]==2*n-2){
pos=i-'a'+1;
}
}
//----------------- YES
printf("YES\n");
for(int i=1;i<=n;i++){
printf("%c",'a'+(pos-1));
}
vis[pos]-=n;
for(char i='a';i<='z';i++){
if((i-'a'+1)!=pos&&vis[i-'a'+1]!=0){
printf("%c",i);
vis[i-'a'+1]--;
break;
}
}
for(int i=1;i<=vis[pos];i++){
printf("%c",'a'+(pos-1));
}
vis[pos]=0;
for(char i='a';i<='z';i++){
ll op=i-'a'+1;
for(int j=1;j<=vis[op];j++){
printf("%c",i);
}
}
return 0;
}
//------------ YES
printf("YES\n");
ll pos=0;
for(char i='a';i<='z';i++){
ll op=i-'a'+1;
if(vis[op]>n){
pos=i-'a'+1;
}
}
for(int i=1;i<=n;i++){
printf("%c",'a'+(pos-1));
}
vis[pos]-=n;
for(char i='a';i<='z';i++){
ll op=i-'a'+1;
if(op!=pos&&vis[op]!=0){
vis[op]--;
printf("%c",i);
break;
}
}
for(int i=1;i<=vis[pos];i++){
printf("%c",'a'+(pos-1));
}
vis[pos]=0;
for(char i='a';i<='z';i++){
ll op=i-'a'+1;
for(int j=1;j<=vis[op];j++){
printf("%c",i);
}
}
}
F 树上博弈
套路题 从根开始搜索 求匹配度
vector<ll>G[111111];
ll dfs(ll s,ll rt){
ll ans=0;
for(int i=0;i<G[s].size();i++){
if(G[s][i]==rt){
continue;}
ans=ans+dfs(G[s][i],s);
}
if(!ans){
return 1;}
return ans-1;
}
signed main()
{
ll n;
read(n);
for(int i=1;i<=n-1;i++){
ll u,v;
read(u);
read(v);
G[u].push_back(v);
G[v].push_back(u);
} // 从根节点
ll flag=dfs(1,0);
if(flag){
printf("Alice");
return 0;
}
printf("Bob");
}
剩下的I J 签到题 没啥写的 - -
cf 698div2 昨晚头疼,打的很烂 ,也确实不会做。 A题没啥好说的统计最多的数字,B题 不知道为什么>= 10d一定是yes。 C题就是根据di 推式子然后模拟过去cheak
推出来就是这个式子 因为题意是 对于任意的ai 都有它的负数存在,那么假设给这个原始a数组分成两部分,1–n 正整数且从小到大排列, n+1–2n就放他们的负数。那么不妨先计算一下d1 ---- dn
根据我草稿纸上面推的那样,得到 di 关于 ai i 以及前缀后缀的表达式子,对于di 相邻做差可以得到ai 与 ai+1 的关系 那么思路就已经浮现了,说到这里应该都会写了
ll d[222222];
map<ll,ll>s;
vector<ll>vis;
map<ll,ll>sb;
signed main()
{
ll t;
read(t);
while(t--)
{
ll n;
read(n);
s.clear();
sb.clear();
vis.clear();
for(int i=1; i<=2*n; i++)
{
read(d[i]);
s[d[i]]++;
}
sort(d+1,d+1+2*n);
ll f=0;
ll num=0;
for(int i=1; i<=2*n; i++)
{
if(s[d[i]]!=2)
{
f++;
break;
}
else
{
if(sb[d[i]]==0)
{
if(d[i]%2!=0)
{
num++;
}
vis.push_back(d[i]);
sb[d[i]]++;
}
}
}
if(f||vis.size()!=n||num!=0)
{
printf("NO\n");
continue;
}
ll gg=0;
ll rnm=vis[0]; // sum *2
ll res=0;
ll opp=0;
for(int i=0; i<vis.size()-1; i++)
{
ll ok=vis[i+1]-vis[i];
if(ok%(2*(i+1))!=0||ok<=0)
{
gg++;
break;
}
ll cnt=ok/(2*(i+1));
res+=opp+cnt;
opp=opp+cnt;
if(cnt<=0)
{
gg++;
break;
}
}
if(gg||(rnm/2-res)<=0||(rnm/2-res)%n!=0)
{
printf("NO\n");
continue;
}
else
{
printf("YES\n");
}
}
}
至于D题为什么是 k -a[i] % gcd 就有解 - - 玄学 难顶 ,不会证明
简单最短路+枚举 暴力就好了
const int manx=1e4+500;
const int mamx=4e5+5;
ll head[manx],d[manx],hurt[manx];
bool vis[manx];
ll k=0,s,e,kk,ans;
struct node{
ll v,next,w;
}a[mamx];
void add(ll u,ll v,ll w)
{
a[++k].next=head[u];
a[k].w=w;
a[k].v=v;
head[u]=k;
}
map<pair<ll ,ll >,ll >dis;
void dij()
{
memset(d,inf,sizeof(d));
memset(vis,0,sizeof(vis));
d[s]=0;
priority_queue<pair<ll,ll> >q;
q.push(mp(0,s));
while(q.size()){
ll u=q.top().se;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=a[i].next){
ll v=a[i].v,w=a[i].w;
if(d[v]>d[u]+w){
//printf("qwq %lld\n",d[v]); //松弛操作,更新距离
d[v]=d[u]+w;
dis[{
s,v}]=d[v];
// printf("sad %lld %lld %lld %lld\n",d[u],u,res,d[v]);
q.push(mp(-d[v],v)); //把更新的距离和点入队,这里距离取负变成小根堆
}
}
}
}
ll pos[60];
map<ll,ll>rnm;
signed main()
{
ll nu;
ll n,m;
read(n);
read(m);
read(nu);
//e=n,s=1;//s代表最短路的起源点
for(int i=1;i<=nu;i++){
read(pos[i]);
rnm[pos[i]]=1;
}
for(int i=1;i<=m;i++)
{
ll u,v,w;
read(u);
read(v);
read(w);
add(u,v,w);
add(v,u,w);
}
sort(pos+1,pos+1+nu);
for(int i=1;i<=nu;i++){
s=pos[i];
dij();
}
ll mi=1e18;
do{
for(int i=1;i<=n;i++){
if(rnm[i]){
continue;}
ll cnt=0;
for(int k=1;k<=nu-1;k++){
cnt+=dis[{
pos[k],pos[k+1]}];
}
cnt=cnt+dis[{
pos[1],i}]+dis[{
pos[nu],i}];
mi=min(mi,cnt);
}
}while(next_permutation(pos+1,pos+1+nu));
printf("%lld",mi);
return 0;
}
补题哦 ! 每次打完比赛都要认真的补题