AtCoder Beginner Contest 403
C - 403 Forbidden
对每个用户,先判断有无所有权限,若无,再判断有无单独查看Y的权限。
过程中用set/map维护即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll=long long;
const ll inf=1e18;
const int mod =1e9+7;
void solve(){
int n,m,q;
cin>>n>>m>>q;
vector<map<int,int>> a(n+10);
map<int,int> mp;
while(q--){
int ch,x,y;
cin>>ch;
if(ch==3){
cin>>x>>y;
if(mp[x]==0 && a[x][y]==0){
cout<<"No\n";
}else{
cout<<"Yes\n";
}
}else if(ch==2){
cin>>x;
mp[x]=1;
}else{
cin>>x>>y;
a[x][y]=1;
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
return 0;
}
D - Forbidden Difference
很典的题,很典的做法。
要删除一些数字,使得不存在 Bi-Bj == D
如果两个数的差值等于D,则这两个数对D取模的值一定相同。
所以,将所有数分成D组,分组依据就是对D取模的值。每组之间互不影响,讨论每组组内最少删除几个即可.
对于一组内的数,可以用dp来计算最少删除几个。
因为值域很小,所以不用真的把组分出来,只需要枚举值域即可。DP 很简单,看代码即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll=long long;
const ll inf=1e18;
const int mod =1e9+7;
const int N=1e6+10;
void solve(){
int n,k;
cin>>n>>k;
int mx=1e6;
vector<int> cnt(1000010);
for(int i=1;i<=n;i++){
int val;
cin>>val;
cnt[val]++;
}
int ans=0;
if(k==0){
for(int i=0;i<=mx;i++){
if(cnt[i]) ans+=cnt[i]-1;
}
cout<<ans<<endl;
return;
}
for(int i=0;i<k;i++){
array<int,2> dp{0,0};
for(int j=i;j<=mx;j+=k){
//1:删 0:不删
array<int,2> tmp{0,0};
tmp[0]=dp[1];
tmp[1]=min(dp[0],dp[1])+cnt[j];
dp=tmp;
}
ans+=min(dp[0],dp[1]);
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
return 0;
}
E - Forbidden Prefix
字典树典题。
字符串分两种,X串和Y串。
需要维护几个数组,flag[i]表示,在字典树的第i个节点,有没有X串在P的位置结束。
当插入一个Y串时,如果Y串的路径上,已有flag[i]=1,则这个路径上存在一个前缀。
插入一个X串时,如果这个X串的终点,已有一些Y串经过,则这些Y串中,还在ans中的应该被减去。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll=long long;
const ll inf=1e18;
const int mod =1e9+7;
const int N=5e5+10;
int ans,idx;
int tr[N][26];
bool flag[N];//第i个节点有无前缀存在
int st[N];// 第i个Y中的字符串还在不在答案里 0在1不在
vector<int> pos[N];
bool vis[N];
int id;
void insert1(string s){
int p=0;//这个字符串最后到的节点
for(auto ch:s){
int val=ch-'a';
if(!tr[p][val]){
tr[p][val]=++idx;
}
p=tr[p][val];
}
flag[p]=1;
for(auto x:pos[p]){
//去掉所有经过p且还在答案里的Y串
if(!vis[x]){
ans--;
vis[x]=1;
}
}
pos[p].clear();
}
void insert2(string s){
int p=0;
id++;// 这个Y串的id
ans++;
for(auto ch:s){
int val=ch-'a';
if(!tr[p][val]){
tr[p][val]=++idx;
}
p=tr[p][val];
pos[p].push_back(id);
if(!vis[id] && flag[p]){
ans--;
vis[id]=1;
break;
}
}
}
void solve(){
int q;
cin>>q;
while(q--){
int t;
string s;
cin>>t>>s;
if(t==1){
insert1(s);
}else{
insert2(s);
}
cout<<ans<<endl;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
return 0;
}
F - Shortest One Formula
当感觉完全没有思路的时候,想想dp
设表示数字i的最短字符串是f[i], 则f[i] 一定是从f[i-j]+f[j] , 和 f[i/j]*f[j]转移过来的
但是当考虑从乘法转移f[i/j] * f[j]时,还要考虑f[i/j]和f[j]最外层的运算符号。举例来说:
假设f[6]=f[2]*f[3], f[2]=1+1, f[3]=1+1+1。 此时不能直接乘起来,因为会变成1+1 * 1+1+1
显然是有问题的,因为此时f[2]或f[3]的最外层运算符是+号
所以还要加一个维度:
f[i][0]表示,结果是i,且最外层运算符是 * 号的表达式。
f[i][1]表示,结果是i,且最外层运算符是 + 号的表达式。
要注意转移的初始值和一些转移过程中的细节
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll=long long;
using lll=__int128_t;
using ull=unsigned long long;
const ll inf=1e18;
const int mod =1e9+7;
string minstr(string &a,string &b){
if(a.empty()) return b;
if(b.empty()) return a;
if(a.size()>b.size()) return b;
return a;
}
void solve(){
int n;
cin>>n;
vector<vector<string>> f(n+10,vector<string>(2));
int k=1;
f[1][0]="1";
f[1][1]=string(10000,'m');
for(int i=2;i<=n;i++){
while(k<i){
k=k*10+1;
}
if(k==i){
f[i][0]=to_string(k);
}
//f[i][0]:最外层是*号连接的 f[i][1]:最外层是由+号连接的
//1. 从加法转移
for(int j=1;j<=i/2;j++){
//f[j]+f[i-j];
string tmp=minstr(f[j][0],f[j][1])+"+"+minstr(f[i-j][0],f[i-j][1]);
if(tmp.size()<f[i][1].size() || f[i][1].size()==0){
f[i][1]=tmp;
}
}
//2. 从乘法转移
for(int j=2;j*j<=i;j++){
if(i%j) continue;
//f[j]*f[i/j]
string fj1="("+f[j][1]+")";
string fij1="("+f[i/j][1]+")";
string tmp=minstr(f[j][0],fj1)+"*"+minstr(f[i/j][0],fij1);
if(tmp.size()<f[i][0].size() || f[i][0].size()==0){
f[i][0]=tmp;
}
}
}
cout<<minstr(f[n][0],f[n][1]);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
return 0;
}

浙公网安备 33010602011771号