Nov 21
依然是爆炸的一天,t1 没写好 100 -> 45,t2 倒是没有挂,t3 数据竟然是随机的,我的暴力跑的飞快,t4 竟然没有推出来无脑 dp, 看来我需要专门找一天疯狂推 dp 式子。
比赛层面
今天专注时间大概有两个小时?其他时间在玩 galgame 和在外边闲逛。
不要太过相信自己的贪心,即使证明出来也要对拍,一般贪心对拍不难写,有的时候策略即使是对的也会出现一些实现上或细节上的问题,s2oj 有传奇捆绑。
快读一定要快。
暴力如果发现有许许多多的剪枝可以加就尽量加,正经比赛没有绑包,很有可能出现一部分随机数据,一棵树硬生生向上跳也成为了 log 级别的。
这一次 t3 我的暴力预计是 50 分的,结果大胆优化到了 65 分,硬生生挤过了一个捆绑包,只能说感谢随机数据,明明可以把我卡到 1e10 的,但是随机就不好说了。
不知道为什么 t4 的无脑 dp 部分分并没有整出来,下次一定。
今天的 t2 我通过打表的方式加速了我想出来正解的过程,拜谢打表大法。
getchar_unlocked 是真的好快,在 T3 这种 time limit 大,输入极其多的题目中真的很牛逼,据说这个是和 fread 坐一桌的。
题目层面
S2OJ 2491
普通题
我们假设删的元素是 \(x,y\),新增的是 \(z=(x\oplus y)\)。
因为最后的答案是 \(\sum 2^{a_i}\),这个东西同二进制有很好的贪心性质。
明显的 \(max(x,y)\ge z\)。
所以我们发现如果两个数字的高处的位是一样的话就不行,而一共只有 60 二进制位的数字,我们发现如果这个东西如果 n > 60 就直接无解了,因为我们没有位置使得这些位都不一样了。
之后我们直接暴力跑 60 就行了。
代码↓
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define getchar getchar_unlocked
using namespace std;
const int MN=1e6+116;
int n, a[MN];
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
x=x*10+ch-'0',ch=getchar();
return x*f;
}
void Solve(){
n=read();
for(int i=1; i<=n; ++i) a[i]=read();
if(n>60){
putchar('N');
putchar('O');
putchar('\n');
return;
}
bool can=true;
for(int i=1; i<=n&&can; ++i){
for(int j=1; j<i&&can; ++j){
if((a[i]^a[j])<=max(a[i],a[j])){
can=false;
}
}
}
if(can){
putchar('Y');
putchar('E');
putchar('S');
putchar('\n');
}
else{
putchar('N');
putchar('O');
putchar('\n');
}
return;
}
signed main(){
int T; T=read(); while(T--) Solve();
return 0;
}
/*
尼马的破涕
*/
S2OJ 2496
简单题
我们首先发现如果一个位置是正确的,我们就绝不动这个位置。
然后有两个情况,一个是交换可以使两个位置正确的,一个是交换可以是一个位置正确的。
再把所有前者都选上,之后讨论剩下的。
我们将所有位置 %4 看,如果一样视为一等。
找一个最大的同位置同字符的次数,我们选择把这个次数的位置留出来,这个样子我们就可以把这些次数省出来。
好题好做。
代码↓
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int MN=1e5+115;
/*
别假求求了,我什么都愿意做的
*/
unordered_map <char,int> trans;
int n; string s;
int cnt[5][5], ans=0;
void Read(){
memset(cnt,0,sizeof(cnt));
cin>>n>>s; s=' '+s;
for(int i=1; i<=n+n+n+n; ++i){
cnt[trans[s[i]]][i%4]++;
}
return;
}
void Solve(){
Read(); ans=0;
cnt[1][1]=cnt[2][2]=cnt[3][3]=cnt[4][0]=0;
for(int i=1; i<=4; ++i){//each ji
int should=i%4;
for(int j=1; j<=4; ++j){
if(i==j) continue;
ans+=min(cnt[i][j%4],cnt[j][should]);
int val=min(cnt[i][j%4],cnt[j][should]);
cnt[i][j%4]-=val;
cnt[j][should]-=val;
}
};
int miao=0, maxn=0;
for(int i=1; i<=4; ++i){
for(int j=0; j<=3; ++j){
miao+=cnt[i][j];
maxn=max(maxn,cnt[i][j]);
}
}
cout<<ans+(miao-maxn)<<'\n';
return;
}
int main(){
//freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
trans['A']=1; trans['C']=2; trans['G']=3; trans['T']=4;
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T; cin>>T; while(T--) Solve();
return 0;
}
/*
啊?
打个表发现神秘规律过大样例?
不是
啊?
希望别假!
求求了
呜呜呜呜呜
如果我的打表做法没有假,我直接 js 到 noip
神人忧郁转换男~
过牌守护钢铁师~
对面铺场不要紧,
一张起义来兜底。
*/
S2OJ 2492
傻逼题。
为什么 noip 模拟赛会出现树链剖分大数据结构题?
不改这个玩意了,写了半天没调出来,放一下我美丽的暴力↓
点击查看代码
#include <bits/stdc++.h>
#define getchar getchar_unlocked
using namespace std;
const int MN=3e6+116;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
x=x*10+ch-'0',ch=getchar();
return x*f;
}
struct Node{
int nxt, to;
}node[MN];
int head[MN], tottt, fa[MN];
void insert(int u, int v){
node[++tottt].to=v;
node[tottt].nxt=head[u];
head[u]=tottt; return;
}
int n, q, a[MN], depth[MN];
void Read(){
n=read(); q=read();
for(int i=1; i<=n; ++i) a[i]=read();
for(int i=1; i<n; ++i){
int u, v; u=read(); v=read();
insert(u,v); insert(v,u);
}
return;
}
void dfs(int u, int father){
fa[u]=father; depth[u]=depth[father]+1;
for(int i=head[u];i;i=node[i].nxt){
int v=node[i].to;
if(v==father) continue;
dfs(v,u);
}
return;
}
int LCA(int x, int y){
if(depth[x]<depth[y]) swap(x,y);
while(depth[x]!=depth[y]) x=fa[x];
if(x==y) return x;
while(fa[x]!=fa[y]) x=fa[x],y=fa[y];
return fa[x];
}
int stk[MN], top=0;
bool work(int pos, int sum){
if(pos==top) return (sum==24);
if(sum>24) return false;
if(work(pos+1,sum*stk[pos+1])) return true;
else return work(pos+1,sum+stk[pos+1]);
}
int Query(int x, int y){
top=0; int lca=LCA(x,y);
vector <int> tmp; tmp.clear();
while(x!=lca){
stk[++top]=a[x];
x=fa[x];
}
stk[++top]=a[lca];
while(y!=lca){
tmp.push_back(a[y]);
y=fa[y];
}
reverse(tmp.begin(),tmp.end());
for(auto v:tmp) stk[++top]=v;
//cout<<'\n';
//for(int i=1; i<=top; ++i) cout<<stk[i]<<" ";
//cout<<'\n';
if(!top) return 0;
return work(1,stk[1]);
}
void Change(int x, int y){
a[x]=y; return;
}
void Solve(){
Read(); dfs(1,1);
while(q--){
int op, x, y;
op=read(); x=read(); y=read();
if(op==2){
Change(x,y);
}else{
cout<<Query(x,y)<<'\n';
}
}
return;
}
int main(){
//freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
Solve();
return 0;
}
/*
加上剪纸大样例跑五秒,这个暴力有前途
看看能不能把大样例卡到 4 s
希望不尽尽是 20 pts
求求了
*/
S2OJ 2497
好题。
我们如果知道了在那个位置结束,我们一定是在保证能到达这个位置的情况下尽可能在前边打,因为体力如果跳过是损耗的,至于如果后边的留些体力过去会更优,我们就不断枚举结束位置,反悔贪心去选择就行了。
代码↓
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MN=1e6+116;
int n, B, a[MN], b[MN], ans=0, A, res;
priority_queue <int> q;
void Read(){
cin>>n>>B;
for(int i=0; i<=n+1; ++i) a[i]=b[i]=0;
for(int i=1; i<=n; ++i) cin>>a[i]>>b[i];
return;
}
void Solve(){
Read();
ans=A=res=0;
while(!q.empty()) q.pop();
for(int i=1; i<=n; ++i){
A+=a[i]; res+=a[i]; ans=max(ans,res);
q.push(b[i]); A-=b[i];
while(!q.empty()&&A<0){
int u=q.top(); A+=q.top()-B;
res-=B; q.pop();
}
if(res<0) break;
}
cout<<ans<<'\n';
return;
}
signed main(){
//freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T; cin>>T; while(T--) Solve();
return 0;
}

浙公网安备 33010602011771号