題目鏈接:https://ac.nowcoder.com/acm/contest/907#question
A.【六】平面
公式:(n*n+n)/2 + 1,n爲直線數目
B.【一】n的約數
枚舉質因子和每個質因子的個數,顯然個數肯定從多到少。
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int mx = 1e4 + 10;
int a[100];
ll n,ans;
void dfs(int x,int d,ll ret,ll now){
ll mi = 1;
for(int i=1;i<=d;i++){
mi *= a[x+1];
if(ret>n/mi) break;
ans = max(ans,now*(i+1));
dfs(x+1,i,ret*mi,now*(i+1));
}
}
int main() {
int t;scanf("%d",&t);
int tot = 0;
for(int i=2;i<100;i++){
bool ok = 0;
for(int j=2;j<i;j++)
if(i%j==0) ok = 1;
if(!ok) a[tot++] = i;
}
while(t--){
scanf("%lld",&n);
ans = 1;
dfs(-1,100,1,1);
printf("%lld\n",ans);
}
return 0;
}
C.【快】Rabbit的數列
直接線段樹+懶人標記,複雜度感覺是不會超過O(n*log(n))。另外這題數據隨機,所以也可以瞎幾把搞。
線段樹複雜度沒有明確證明,口胡吧O(∩_∩)O哈哈~
#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef long long ll;
using namespace std;
const int mx = 1e5 + 10;
int n,m,C;
int x,y,a,b,cnt[mx];
int v[mx<<2],lazy[mx<<2];
void build(int l,int r,int rt)
{
if(l==r){
lazy[rt] = 1;
return ;
}
int mid = l+r>>1;
build(lson);build(rson);
lazy[rt] = 1;
}
int query(int l,int r,int rt,int c)
{
int mid = l+r>>1;
if(c==1){
if(lazy[rt]){
if(lazy[rt]==x) return r-l+1;
return 0;
}
return query(lson,c) + query(rson,c);
}else{
if(lazy[rt]){
cnt[lazy[rt]] += r-l+1;
return 0;
}
return query(lson,c) + query(rson,c);
}
return 0;
}
void push_up(int rt){
if(lazy[rt]){
lazy[rt<<1] = lazy[rt];
lazy[rt<<1|1] = lazy[rt];
lazy[rt] = 0;
}
}
void update(int l,int r,int rt,int L,int R,int d)
{
if(L<=l&&r<=R){
lazy[rt] = d;
return ;
}
push_up(rt);
int mid = (l+r)>>1;
if(L<=mid) update(lson,L,R,d);
if(R>mid) update(rson,L,R,d);
if(lazy[rt<<1]==lazy[rt<<1|1])
lazy[rt] = lazy[rt<<1];
}
int main() {
scanf("%d%d%d",&n,&C,&m);
build(1,n,1);
while(m--){
scanf("%d%d%d%d",&x,&y,&a,&b);
int now = query(1,n,1,1);
int L = (a+(1ll*now+b)*(1ll*now+b))%n;
int R = (a+(1ll*now*b%n)*(1ll*now*b%n))%n;
L++,R++;
if(L>R) swap(L,R);
update(1,n,1,L,R,y);
}
query(1,n,1,2);
int ans = 0;
for(int i=1;i<=C;i++) ans = max(ans,cnt[i]);
printf("%lld\n",ans);
return 0;
}
D.【樂】k進制數
由於這個題求的是一個字符串所有的子串有多少數字滿足k進制下d(x)=b,這個數字很明顯會滿足一些性質。 考 慮這個每次轉化的過程,每一次進位相當於把一個k轉化成了一個1,也就是說,在數位和mod(k-1)的意義下, 轉化前和轉化後的數字是等價的,最終會成爲(x-1)mod(k-1)+1然後就不能動了 如果b=0,那麼顯然只有這 個串的所有數字都爲0(也就是說這個數字爲0)才成立,否則一個串一定不能轉化爲0否則這個串的和一定在mod(k-1)的意義下和b(mod(k-1))等價,這裏簡單的前綴和或者維護一個偏置值,維護前面的和(用map啥的)都 可以做 所以總之按照b=0分類,然後分類計算一下即可。
#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef long long ll;
using namespace std;
const int mx = 1e5 + 10;
int n,m,K,a[mx];
ll pre[mx];
int cnt[mx];
map <int,int> mp;
int main() {
scanf("%d%d%d",&K,&m,&n);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
pre[i] = pre[i-1] + a[i];
cnt[i] = 0;
if(!a[i]) cnt[i] = cnt[i-1] + 1;
}
ll ans = 0;
mp[0] = 1;
for(int i=1;i<=n;i++){
if(m==K-1){
int c = pre[i]%(K-1);
ans += mp[c] - cnt[i];
}else if(m==0){
ans += cnt[i];
}else{
int c = pre[i]%(K-1);
c = (c-m+(K-1))%(K-1);
ans += mp[c];
}
if(!mp.count(pre[i]%(K-1))) mp[pre[i]%(K-1)] = 1;
else mp[pre[i]%(K-1)]++;
}
printf("%lld\n",ans);
return 0;
}
E.【中】假的字符串
首先建一個字典樹,然後呢根據大小關係在當前轉態下建立某個字符與其他字符的大小關係,然後拓撲排序看下是否有解。
還有注意的是如果該字符串包含了其他的串,那麼肯定無解。
#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef long long ll;
using namespace std;
const int mx = 3e4 + 10;
string s[mx];
int n,rt,tot;
int nxt[mx*10][26];
int vis[33],in[33];
bool ok[mx],eng[mx*10];
vector <int> g[33];
void add(int x){
int now = rt;
for(int i=0;i<s[x].length();i++){
int id = s[x][i] - 'a';
if(!nxt[now][id])
nxt[now][id] = tot++;
now = nxt[now][id];
}
eng[now] = 1;
}
bool toupu(){
int siz = 0;
queue <int> q;
for(int i=0;i<26;i++){
if(!in[i]) q.push(i),siz++;
}
while(!q.empty()){
int u = q.front();
q.pop();
for(int v:g[u]){
in[v]--;
if(!in[v]) q.push(v),siz++;
}
}
return siz==26;
}
bool check(int x){
int now = rt,c = 0;
for(int i=0;i<30;i++) g[i].clear();
memset(in,0,sizeof(in));
for(int i=0;i<s[x].length();i++){
int id = s[x][i] - 'a';
if(i!=s[x].length()-1&&eng[nxt[now][id]])
return 0;
for(int j=0;j<26;j++){
if(j!=id&&nxt[now][j]){
g[id].push_back(j);
in[j]++;
}
}
now = nxt[now][id];
}
return toupu();
}
int main() {
ios::sync_with_stdio(false);
cin >> n;
rt = tot++;
for(int i=0;i<n;i++) cin >> s[i],add(i);
int ans = 0;
for(int i=0;i<n;i++){
if(check(i)){
ans++;
ok[i] = 1;
}
}
cout << ans << endl;
for(int i=0;i<n;i++){
if(ok[i]) cout << s[i] << endl;
}
return 0;
}
F.【獎】出題人的無向圖
一個個分開處理肯定是不行的,那麼我考慮離線,將查詢的vi從小到大排序,相當於越往後就會有新的點被加入進來。
然後就是並查集+啓發式合併,小的樹合併到大的樹上面去,另外k個點隨便用set暴力刪除然後再暴力插入即可。
#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define fi first
#define se second
typedef long long ll;
using namespace std;
const int mx = 2e5 + 10;
int n,m,K,a[mx],b[mx];
int ret[mx*3],fa[mx],cnt[mx];
multiset <int> st;
vector <int> g[mx];
map <int,int> mp[mx];
int find(int x){
return x==fa[x]? x:fa[x]=find(fa[x]);
}
struct node{
int p,v;
bool operator < (node A)const{return v < A.v;}
}s[mx];
struct edge{
int v,p;
vector<int> r;
bool operator < (edge A)const{return v < A.v;}
}e[mx*3];
void merge(int x,int y){
x = find(x);
y = find(y);
if(x==y) return ;
st.erase(st.find(cnt[x]));
st.erase(st.find(cnt[y]));
if(mp[x].size()<mp[y].size()) swap(x,y);
fa[y] = x;
for(auto it:mp[y]){
if(mp[x][it.fi]&&mp[x][it.fi]%K==0) cnt[x]--;
mp[x][it.fi] += it.se;
if(mp[x][it.fi]%K==0) cnt[x]++;
}
st.insert(cnt[x]);
}
void add(int p){
fa[p] = p;
mp[p][b[p]] = 1;
if(K==1) cnt[p] = 1;
st.insert(cnt[p]);
for(int v:g[p]) if(fa[v]){
merge(p,v);
}
}
int solve(int p,int x){
while(p<=n&&s[p].v<=e[x].v) add(s[p++].p);
int siz = e[x].r.size();
set <int> s1;
for(int i=0;i<siz;i++) if(fa[e[x].r[i]])
s1.insert(find(e[x].r[i]));
for(auto it:s1)
st.erase(st.find(cnt[it]));
if(st.empty()) ret[e[x].p] = 0;
else ret[e[x].p] = *st.rbegin();
for(auto it:s1) st.insert(cnt[it]);
return p;
}
int main(){
scanf("%d%d%d",&n,&m,&K);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
s[i].v = a[i],s[i].p = i;
}
for(int i=1;i<=n;i++) scanf("%d",b+i);
int u,v,q;
while(m--){
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d",&e[i].v);
e[i].p = i;
scanf("%d",&u);
for(int j=1;j<=u;j++){
scanf("%d",&v);
e[i].r.push_back(v);
}
}
sort(s+1,s+1+n);
sort(e+1,e+1+q);
for(int i=1,p=1;i<=q;i++)
p = solve(p,i);
for(int i=1;i<=q;i++) printf("%d\n",ret[i]);
return 0;
}