比赛链接:长安大学校赛-2017
A:水
#include
using namespace std;
int a[10]={1,0,0,0,0,0,1,0,2,1};
int main()
{
int x,T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&x);
if(x==0)
{
puts("1");
continue;
}
int ans=0;
while(x)
{
ans+=a[x%10];
x/=10;
}
printf("%d\n",ans);
}
return 0;
}
B:贪心,每遇到一个字符,将其移动到合理的地方。
#include
using namespace std;
typedef long long ll;
const ll INF=1e18+7;
char s[200007];
int main()
{
int T,n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
scanf("%s",s);
n=n*2;
ll ans=INF,res=0;
int g=0,b=0;
//GBGB
for(int i=0;iif(s[i]=='G'&&b>g) res+=b-g;
else if(s[i]=='B'&&g>b) res+=g-b-1;
if(s[i]=='G') g++;
else b++;
}
ans=min(ans,res);
//BGBG
res=0;
g=b=0;
for(int i=0;iif(s[i]=='G'&&b>g) res+=b-g-1;
else if(s[i]=='B'&&g>b) res+=g-b;
if(s[i]=='G') g++;
else b++;
}
ans=min(ans,res);
cout << ans << endl;
}
return 0;
}
D:我们将询问按照 x 排序,每得到一个询问将剩余的满足 a[i]>=x 的 b[i] 放入到数据结构中,然后查询区间 [L,R] 内大于等于 y 的元素数量,可以用到分块+二分的数据结构离线动态查询(因为不会树套树)。
见:Codeforces-785E-Anton and Permutation(分块区间查询,动态查询[l,r]内小于某个值的元素个数)
#include
#define mp make_pair
#define fi first
#define se second
using namespace std;
const int maxn=1e5+7;
int a[maxn],b[maxn],bl,sz,n,p[maxn],ans[maxn];
struct Block
{
int l,r,len;
vector<int> arr;
};
struct Query
{
int l,r,x,y,id;
bool operator < (const Query & r) const
{
return x>r.x;
}
}Q[maxn];
Block block[350];
void init_block()
{
for(int i=1;i<=sz;i++) block[i].len=0,block[i].arr.clear();
for(int i=1;i<=n;i++)
{
int j=(i-1)/bl+1;
if(!block[j].len) block[j].l=i;
block[j].r=i;
block[j].arr.push_back(0);
block[j].len++;
}
}
int query(int L,int R,int x,int y)
{
int l=(L-1)/bl+1,r=(R-1)/bl+1;
int res=0;
if(l==r)
{
for(int i=L;i<=R;i++)
res+=(a[i]>=x&&b[i]>=y);
}
else
{
for(int i=l+1;ifor(int i=L;i<=block[l].r;i++)
res+=(a[i]>=x&&b[i]>=y);
for(int i=block[r].l;i<=R;i++)
res+=(a[i]>=x&&b[i]>=y);
}
return res;
}
void update(int x)
{
int X=(x-1)/bl+1;
vector<int> &arr=block[X].arr;
arr.erase(arr.begin());
arr.insert(lower_bound(arr.begin(),arr.end(),b[x]),b[x]);
}
bool cmp(int a,int b)
{
return ::a[a]>::a[b];
}
int main()
{
int m,T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=n;i++) p[i]=i;
sort(p+1,p+1+n,cmp);
bl=sqrt(n);sz=(n-1)/bl+1;
init_block();
for(int i=0;iscanf("%d%d%d%d",&Q[i].l,&Q[i].r,&Q[i].x,&Q[i].y);
Q[i].id=i;
}
sort(Q,Q+m);
int cur=1;
for(int i=0;iwhile(cur<=n&&a[p[cur]]>=Q[i].x) update(p[cur++]);
ans[Q[i].id]=query(Q[i].l,Q[i].r,Q[i].x,Q[i].y);
}
for(int i=0;iprintf("%d\n",ans[i]);
}
return 0;
}
E:设 dp[i] 为前 i 个的方案数,
dp[i]=∑[j,i]不含重复元素dp[j]
#include
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll dp[100007];
char s[100007];
int a[100007];
bool vis[26];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",s+1);
int n=strlen(s+1);
for(int i=1;i<=n;i++) a[i]=s[i]-'a';
dp[0]=1;
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
dp[i]=0;
for(int j=i;j>=1;j--)
{
if(!vis[a[j]])
{
vis[a[j]]=true;
dp[i]=(dp[i]+dp[j-1])%mod;
}
else break;
}
}
cout << dp[n] << endl;
}
return 0;
}
G:同一个集合中的任意两点间没有边,表现在补图中就是完全图,不同集合间的任意两点间有边,表现在补图中就是不同的集合属于不同的联通集。所以我们处理出补图,进行上述的检测就行了。
#include
using namespace std;
const int maxn=1007;
bool G[maxn][maxn],vis[maxn];
vector<int> adj[maxn],p;
void dfs(int u)
{
vis[u]=true;
p.push_back(u);
for(int i=0;iint v=adj[u][i];
if(vis[v]) continue;
dfs(v);
}
}
bool check()
{
int n=p.size();
for(int i=0;ifor(int j=i+1;jint u=p[i],v=p[j];
if(G[u][v]) return false;
}
return true;
}
int main()
{
int n,m;
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(G,0,sizeof(G));
memset(vis,0,sizeof(vis));
int u,v;
while(m--)
{
scanf("%d%d",&u,&v);
G[u][v]=G[v][u]=true;
}
for(int i=1;i<=n;i++) adj[i].clear();
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(!G[i][j])
{
adj[i].push_back(j);
adj[j].push_back(i);
}
int k=0;
bool flag=true;
for(int i=1;i<=n;i++)
{
p.clear();
if(!vis[i])
{
dfs(i);
if(check()) ++k;
else
{
flag=false;
break;
}
}
}
if(flag&&k>=2) printf("%d\n",k);
else puts("0");
}
return 0;
}
J:枚举每个字母就行。
#include
using namespace std;
typedef long long ll;
const int INF=1e9+7;
char s[100007];
int a[100007];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
scanf("%s",s);
int l=n*m;
for(int i=0;i'a';
ll ans=0;
for(int i=0;iint res=INF;
for(int k=0;k<26;k++)
{
int t=0;
for(int j=0;jabs(a[i+j*n]-k);
res=min(t,res);
}
ans+=res;
}
cout << ans << endl;
}
return 0;
}
L:处理出所有符合条件的数,然后二分查询就行了。
#include
using namespace std;
typedef long long ll;
vector a;
int main()
{
int T;
scanf("%d",&T);
for(int i=1;i<=6;i++)
{
for(int j=1;j<=9;j++)
{
for(int k=0;k<=9;k++)
{
ll t=0;
for(int p=0;p10,t+=j;
for(int p=i;p<2*i;p++) t*=10,t+=k;
for(int p=2*i;p<3*i;p++) t*=10,t+=j;
a.push_back(t);
}
}
}
sort(a.begin(),a.end());
while(T--)
{
ll l,r;
cin>>l>>r;
int ans=upper_bound(a.begin(),a.end(),r)-a.begin();
ans-=lower_bound(a.begin(),a.end(),l)-a.begin();
printf("%d\n",ans);
}
return 0;
}