IME Starters Try-outs 2018
Codeforces Gym三星场的训练,主要是为了保持稳定的输出~
简单地分析一下这场个人训练赛
- 4min,A题AC
- 然后觉得F可做,直接按层数的奇偶性分类WA11
- D题一个裸的线段树施展了13min...
- 用了4min写了F的树形DP
- 11min搞定了G题。理解题意后就是一个
插板
问题了 - 23min过了B,很多时间用在了读题上
- 15min过了E,一个很裸的最大生成树
79min 6题
之后的题,难度稍微大了一点。
- J题的做法:如果没有加密操作,Trie树可以解决问题。对于加密操作,我们可以施展时间魔法,每一次加密,时间戳
T++
,然后T
时刻插入一个串或者查询一个串,我们可以让这个串时间倒流T
,这样集合内的每个串都站在了同一起跑线上。问题也就可以通过Trie树解决了。 - 用了35min,一开始一直想把加密拆成若干个置换群,然后对于所有查询,对每个置换群分别check.....然而并不好搞。
J题大部分时间都用在了想假算法上。代码比较顺利
I题的做法:n是一个循环节。所以有
c/n
个完整的循环,ans+=c/n
,然后加上最后一个不完整的循环节对答案的贡献,我们找到关于x
的方程kx%n=d
的最小正整数解并与c%n
比较大小即可。
kx%n=d
=> kx-ny=d
=> kx+n(-y)=d
x是可以通过exgcd求出的
- I用了40分钟,一开始没看到n是质数....然后被EXGCD搞了....
- C题用了28min,找到一组最优解后没有退出循环WA了一发(最优解未必唯一啊)
- H题用了50min.....从读题到第一发提交之间用了24min
nod
和now
变量之间typo了一下,就GG了。
在H和I的代码上,长时间卡顿,很卜啊!!!!
###code
A
按题意模拟即可
#include <iostream>
using namespace std;
int n, x;
int main() {
scanf("%d",&n);
int ans=0,sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&x);
sum+=x;
if(sum<0) ans=max(ans,-sum);
}
cout<<ans<<endl;
}
B
背包+输出解
#include <iostream>
#include <vector>
using namespace std;
string str[1002]; int val[1002];
int kit, m;
int s[1002], w[1002];
int n, x;
int dp[1002][2002], pre[1002][2002];
int main() {
scanf("%d%d",&kit,&m);
for(int i=1;i<=m;i++) {
cin>>str[i];
scanf("%d",&val[i]);
}
dp[0][0]=1;
for(int i=0;i<m;i++){
for(int j=0;j<2002;j++){
if(dp[i][j] == 0) continue;
dp[i+1][j]=1, pre[i+1][j]=j;
if(j<=1000) {
dp[i+1][j+val[i+1]]=1, pre[i+1][j+val[i+1]]=j;
}
}
}
scanf("%d", &n);
for(int i=1;i<=n;i++) {
scanf("%d",&x);
int need = (x+1)/2 - kit;
int j=-1;
for(j=need;j<2002;j++)
if(dp[m][j] == 1)
break;
if (j==2002) {
printf("-1\n"); continue;
}
int now = m, weight = j;
vector<int> ret;
while(true) {
if (now==0) break;
int tmp = pre[now][weight];
if (weight != tmp) ret.push_back(now);
now --, weight = tmp;
}
cout << ret.size();
for(int j=0;j<ret.size();j++) {
cout << " " << str[ret[j]];
}
cout << endl;
}
}
C
状压DP
#include <iostream>
#include <vector>
using namespace std;
const int INF = 1000000007;
int n,a;
struct Mat {
char pix[22][22];
void init() {
for(int i=0;i<21;i++)
for(int j=0;j<21;j++)
pix[i][j]='0';
}
void read() {
for(int i=0;i<21;i++)
scanf("%s",pix[i]);
}
} mat[22];
int dis(Mat A, Mat B) {
int ans=0;
for(int i=0;i<21;i++)
for(int j=0;j<21;j++)
if(A.pix[i][j]!=B.pix[i][j])
ans++;
return ans;
}
int d[22][22];
int dp[1<<19][19];
pair<int,int> pre[1<<19][19];
vector<int> result;
void print(int s, int pos) {
if (s == 0) return;
int fi = pre[s][pos].first;
int se = pre[s][pos].second;
if (fi == s) result.push_back(-1);
else result.push_back(pos+1);
print(fi, se);
}
int main() {
scanf("%d%d",&n,&a);
mat[n].init();
for(int i=0;i<n;i++) mat[i].read();
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
d[i][j] = dis(mat[i], mat[j]);
for(int i=0;i<=n;i++)
for(int j=0;j<(1<<n);j++)
dp[j][i]=INF;
dp[0][n] = 0;
for(int S=0;S<(1<<n);S++) {
for(int bit=0;bit<=n;bit++) {
if(bit != n && ((S>>bit)&1) == 0) continue;
if (dp[S][bit]+a < dp[S][n]) {
dp[S][n]=dp[S][bit]+a;
pre[S][n]=make_pair(S,bit);
}
for(int i=0;i<n;i++) {
if ((S>>i)&1) continue;
if (dp[S][bit] + d[bit][i] < dp[S|(1<<i)][i]) {
dp[S|(1<<i)][i] = dp[S][bit]+d[bit][i];
pre[S|(1<<i)][i] = make_pair(S, bit);
}
}
}
}
int bst = INF;
for(int i=0;i<n;i++) {
if(dp[(1<<n)-1][i] < bst) bst = dp[(1<<n)-1][i];
}
for(int i=0;i<n;i++) {
if(dp[(1<<n)-1][i]==bst) {
printf("%d\n", bst);
print((1<<n)-1, i);
break;
}
}
for(int i=(int)result.size()-1;i>=0;i--) {
if (result[i] == -1)
printf("*\n");
else
printf("%d\n", result[i]);
}
}
D
直接上线段树吧
#include <iostream>
using namespace std;
const int N = 100000+10;
double sum[N<<2],a[N];
void build(int l,int r,int rt) {
if(l==r) {
sum[rt]=a[l]; return;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int l,int r,int rt,int pos,double x) {
if(l==r) {
sum[rt]+=x;return;
}
int mid=(l+r)>>1;
if(pos<=mid) update(l,mid,rt<<1,pos,x);
else update(mid+1,r,rt<<1|1,pos,x);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
double query(int l,int r,int rt,int L,int R){
if(L<=l&&r<=R) return sum[rt];
int mid=(l+r)>>1;
double ans=0;
if(L<=mid) ans+=query(l,mid,rt<<1,L,R);
if(R >mid) ans+=query(mid+1,r,rt<<1|1,L,R);
return ans;
}
int n;
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lf",&a[i]);
}
build(1,n,1);
int q; scanf("%d",&q);
while(q--) {
int op; scanf("%d",&op);
if(op==1) {
int pos; double x;
scanf("%d%lf",&pos,&x);
update(1,n,1,pos,x-a[pos]);
a[pos]=x;
} else {
int l,r;scanf("%d%d",&l,&r);
double s=query(1,n,1,l,r)/(r-l+1);
printf("%.8f\n", s);
}
}
}
E
最大生成树
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 2000000+10;
vector<int> g[N];
struct Edge {
int u,v,w;
bool operator < (const Edge & o) const {
return w > o.w;
}
} edge[N]; int tot=0;
int par[N], father[N];
int find(int x) {
if (par[x]==-1) return x;
return par[x]=find(par[x]);
}
int n;
void dfs(int u,int p) {
father[u] = p;
for(int i=0;i<g[u].size();i++) {
int v=g[u][i]; if(v==p) continue;
dfs(v, u);
}
}
int main() {
scanf("%d", &n);
for(int i=2;i<=n;i++) {
for(int j=1;j<i;j++) {
int x;
scanf("%d", &x);
edge[++tot].u = i;
edge[tot].v = j;
edge[tot].w = x;
}
}
sort(edge+1,edge+1+tot);
for(int i=1;i<=n;i++) par[i]=-1;
int cost = 0;
for(int i=1;i<=tot;i++) {
if (find(edge[i].u) != find(edge[i].v)) {
g[edge[i].u].push_back(edge[i].v);
g[edge[i].v].push_back(edge[i].u);
cost += edge[i].w;
par[find(edge[i].u)] = find(edge[i].v);
}
}
dfs(1, -1);
printf("%d\n", cost);
for(int i=2;i<=n;i++) {
printf("%d\n", father[i]);
}
}
F
树形DP.
#include <iostream>
#include <vector>
using namespace std;
const int N = 100000+10;
vector<int> g[N];
int n,m;
int dp[N][2];
void dfs(int u,int p) {
dp[u][0]=0;dp[u][1]=1;
for(int i=0;i<g[u].size();i++) {
int v=g[u][i];
if(v==p) continue;
dfs(v,u);
dp[u][0]+=max(dp[v][0],dp[v][1]);
dp[u][1]+=dp[v][0];
}
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
int u,v;scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,-1);
printf("%d\n", max(dp[1][0],dp[1][1]));
}
G
排列组合+推公式
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 300000+10;
const LL MOD = 1000000007;
LL f[N],p[N];
LL mpow(LL a,LL x){
if(x==0) return 1;
LL t=mpow(a,x>>1);
if(x%2==0) return t*t%MOD;
return t*t%MOD*a%MOD;
}
LL C(int x,int y) {
LL ans=f[x];
ans=ans*mpow(f[y],MOD-2)%MOD;
ans=ans*mpow(f[x-y],MOD-2)%MOD;
return ans;
}
int main() {
f[0]=1,p[0]=1;
for(int i=1;i<N;i++) {
f[i]=f[i-1]*(LL)i%MOD;
p[i]=p[i-1]*6LL%MOD;
}
int c,n;cin>>n>>c;
LL ans=C(c-2*n,n)*p[n]%MOD*f[n]%MOD;
printf("%lld\n", ans);
}
H
最短路
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int N = 4000000+10;
const int INF = 1000000007;
vector< pair<int,int> > g[N];
int n,m,q;
int vis[N], dis[N];
struct Nod {
int pos, flight, cost;
bool operator < (const Nod & o) const {
return cost > o.cost;
}
};
int id(int pos,int cnt) {
return pos * 1010 + cnt;
}
void dijkstra() {
for(int i=0;i<N;i++) dis[i]=INF, vis[i]=0;
dis[id(1,0)]=0;
priority_queue<Nod> q;
Nod nod; nod.pos=1,nod.flight=0,nod.cost=0;
q.push(nod);
while (q.size()) {
Nod now = q.top(); q.pop();
int u = id(now.pos, now.flight);
if (vis[u]) continue;
vis[u] = 1;
for(int i=0;i<g[u].size();i++) {
int v = g[u][i].first;
if (vis[v] == 0 && dis[u]+g[u][i].second <= dis[v]) {
dis[v] = dis[u] + g[u][i].second;
nod.pos=v/1010, nod.flight=now.flight+1, nod.cost=dis[v];
q.push(nod);
}
}
}
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
for(int j=0;j<=1000;j++) {
g[id(u,j)].push_back(make_pair(id(v,j+1), w));
//g[id(v,j)].push_back(make_pair(id(u,j+1), w));
}
}
dijkstra();
int q; scanf("%d",&q);
while(q--) {
int d,k;
scanf("%d%d",&d,&k);
int res = INF; k++;
for(int i=0;i<=k;i++) {
if(dis[id(d,i)]<=res){
res=dis[id(d,i)];
}
}
if (res<10000000) {
printf("=] %d\n", res);
} else {
printf("=[\n");
}
}
}
I
扩展欧几里得
#include <iostream>
using namespace std;
typedef long long LL;
int n, k, q;
LL exgcd(LL a, LL b, LL& x, LL& y) {
if(!b) {
x = 1; y = 0; return a;
}
LL r = exgcd(b,a%b,y,x);
y -= a/b*x;
return r;
}
int main() {
scanf("%d %d %d", &n, &k, &q);
while (q --) {
int c, d;
scanf("%d %d", &c, &d);
if (k%n==0) {
if (d==0) printf("%d\n", c);
else printf("0\n");
continue;
}
int ans = c / n;
int rem = c % n; // x [0, rem)
// k*x + n*(-y) = d
LL x, y;
exgcd(k, n, x, y);
x *= d;
x = (x%n+n)%n;
if (x<rem) ans++;
printf("%d\n", ans);
}
}
J
#include <iostream>
using namespace std;
const int N = 500000+10;
int n,m;
char s[N];
int ch[N][30], size;
int T = 0;
void insert(char * s) {
int now = 0;
for(int i=0;s[i];i++) {
int c=s[i]-'A';
if (!ch[now][c]) {
ch[now][c]=++size;
}
now=ch[now][c];
}
}
bool match(char * s) {
int now=0;
for(int i=0;s[i];i++) {
int c=s[i]-'A';
if(!ch[now][c]) return false;
now=ch[now][c];
}
return 1;
}
int nex[N], len[N], vis[N];
int cnt = 0;
void dfs(int u) {
cnt ++; vis[u] = 1;
if (vis[nex[u]] == 0)
dfs(nex[u]);
}
void init() {
for(int i=0;s[i];i++) {
nex[i] = s[i]-'A';
}
for(int i=0;i<n;i++) {
if (vis[s[i]-'A']) continue;
cnt = 0;
dfs(s[i]-'A');
int st = s[i]-'A';
len[st] = cnt;
int now = st;
while(nex[now] != st) {
now = nex[now];
len[now] = cnt;
}
}
}
int main() {
scanf("%d %d", &n, &m);
scanf("%s", s);
init();
for(int i=1;i<=m;i++) {
int op;
scanf("%d", &op);
if (op==1) {
scanf("%s", s);
for(int i=0;s[i];i++) {
// shift -T
int mv = (-T % len[s[i]-'A'] + len[s[i]-'A']) % len[s[i]-'A'];
int now = s[i]-'A';
while(mv --) now = nex[now];
s[i] = 'A' + now;
}
insert(s);
}
if (op==2) {
T ++;
}
if (op==3) {
scanf("%s", s);
for(int i=0;s[i];i++) {
// shift -T
int mv = (-T % len[s[i]-'A'] + len[s[i]-'A']) % len[s[i]-'A'];
int now = s[i]-'A';
while(mv --) now = nex[now];
s[i] = 'A' + now;
}
if (match(s)) printf("YES\n");
else printf("NO\n");
}
}
}