2020ICPC·小米 网络选拔赛第一场 部分题解
Problem A
第一眼上去就直接筛,然后判断丢到map里面就好了,这个做法是会T掉的,考虑一下dp,dp的想法只需要在筛的时候判断一下就好了。因为这题在逻辑上是可以由上一个状态转移过来的,每个数的集合等于我这个数的个数和前面合法子集的最大值相加,所以我们只需要在筛的过程中做dp递推就好了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e7+10;
typedef long long ll;
void check_max (int &a,int b) { a=max (a,b);}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
int vis[maxn],a[maxn];
int dp[maxn];
void solve () {
int n;
scanf ("%d",&n);
for (int i=1,num;i<=n;i++) {
scanf ("%d",&num);
a[num]++;
vis[num]=1;
}
int ans=0;
for (int i=1;i<maxn;i++) {
if (vis[i]==1) {
dp[i]+=a[i];
for (int j=i+i;j<maxn;j+=i) {
if (vis[j]) check_max (dp[j],dp[i]);
}
}
check_max (ans,dp[i]);
}
printf ("%d\n",ans);
}
int main () {
int t;
scanf ("%d",&t);
while (t--) {
solve ();
}
return 0;
}
Problem C
老水了。
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<bitset>
#include<set>
#include<map>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#pragma GCC optimize(2)
#define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define MT(x,i) memset(x,i,sizeof(x) )
#define rev(i,start,end) for (int i=start;i<end;i++)
#define inf 0x3f3f3f3f
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
#define MOD 1000000007
#define exp 1e-8
#define N 1000005
#define fi first
#define se second
#define pb push_back
typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
typedef vector <int> VI;
typedef pair<int ,int> PII;
typedef pair<int ,PII> PIII;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
void check_max (int &a,int b) { a=max (a,b);}
void check_min (int &a,int b) { a=min (a,b);}
const int maxn=2e5+10;
bool is_prime[maxn];
void solve () {
string s;
cin>>s;
vector <int> v;
int cnt=0;
rev (i,0,s.size ()) {
if (s[i]=='w') cnt++;
if (cnt!=0&&s[i]!='w') {
v.pb (cnt);
cnt=0;
}
if (i==s.size ()-1&&cnt!=0) v.pb (cnt);
}
int ans=0;
for (auto it:v) ans+= (2*it-1);
cout<<ans<<endl;
return ;
}
int main () {
ios::sync_with_stdio (false);
solve ();
return 0;
}
Problem I
常规bfs了,首先枚举四周墙壁的非法点,然后往内bfs做标记就好了。
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<bitset>
#include<set>
#include<map>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#pragma GCC optimize(2)
#define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define MT(x,i) memset(x,i,sizeof(x) )
#define rev(i,start,end) for (int i=start;i<end;i++)
#define inf 0x3f3f3f3f
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
#define MOD 1000000007
#define exp 1e-8
#define N 1000005
#define fi first
#define se second
#define pb push_back
typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
typedef vector <int> VI;
typedef pair<int ,int> PII;
typedef pair<int ,PII> PIII;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
void check_max (int &a,int b) { a=max (a,b);}
void check_min (int &a,int b) { a=min (a,b);}
const int maxn=1e3+10;
int n,m;
char maze[maxn][maxn];
int flag[maxn][maxn];
map <char,PII> mp;
int vis[maxn][maxn];
int moving[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
bool check (int x,int y) {
if (vis[x][y]==0&&x>=1&&y<=m&&x<=n&&y>=1) return true;
else return false;
}
void bfs (int x,int y) {
queue <PII> q;
q.push ({x,y});
vis[x][y]=1;
while (q.size ()) {
PII now=q.front (); q.pop ();
rep (i,0,3) {
int dx=now.first+moving[i][0];
int dy=now.second+moving[i][1];
if (mp[maze[dx][dy]].first==(-moving[i][0])) {
if (mp[maze[dx][dy]].second==(-moving[i][1])&&check (dx,dy)) {
vis[dx][dy]=1;
q.push ({dx,dy});
}
}
}
}
return ;
}
void solve () {
cin>>n>>m;
set <PII> s;
rep (i,1,n)
rep (j,1,m) {
cin>>maze[i][j];
if (i==1&&maze[i][j]=='W') s.insert ({i,j});
if (i==n&&maze[i][j]=='S') s.insert ({i,j});
if (j==1&&maze[i][j]=='A') s.insert ({i,j});
if (j==m&&maze[i][j]=='D') s.insert ({i,j});
}
for (auto it:s) bfs (it.first,it.second);
rep (i,1,n)
rep (j,1,m) if (vis[i][j]) s.insert ({i,j});
cout<<s.size ()<<endl;
return ;
}
int main () {
mp['W']={-1,0},mp['A']={0,-1};
mp['S']={1,0},mp['D']={0,1};
ios::sync_with_stdio (false);
solve ();
return 0;
}
Problem J
就是我们能减就减,如果当前值不为0那么我们就构造以他为左上角的矩阵使矩阵的值全部减去当前值,如果遍历的过程中发现有负值那么就不能成功。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
typedef long long ll;
void check_max (int &a,int b) { a=max (a,b);}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
ll s[maxn][maxn],dp[maxn][maxn];
int n,m,a,b;
void solve () {
memset (dp,0,sizeof (dp));
scanf ("%d%d%d%d",&n,&m,&a,&b);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) scanf ("%lld",&s[i][j]);
for (int i=1;i<=n;i++)
for (int j=1,x;j<=m;j++) {
dp[i][j]+=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1];
x=s[i][j]+dp[i][j];
if (x==0) continue;
else if (x<0) {
puts ("QAQ");
return ;
}
else if (x>0) {
if (i+a-1>n||j+b-1>m) {
puts ("QAQ");
return ;
}
dp[i][j]-=x;
dp[i][j+b]+=x;
dp[i+a][j]+=x;
dp[i+a][j+b]-=x;
}
}
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) if (s[i][j]+dp[i][j]) {
puts ("QAQ");
return ;
}
puts ("^_^");
return ;
}
int main () {
int t;
scanf ("%d",&t);
while (t--) {
solve ();
}
return 0;
}