2023信友队提高组复赛冲刺班 10.6赛后总结

发布时间 2023-10-07 23:05:11作者: 质朴青年

T1:Language

注意到单词长度是无限的这个条件,分类讨论它的循环节"PIG" "IGP" "GPI"

将要操作的单词的每一位分别与三个循环节作比较,用前缀和维护其每一个子串需要修改的次数,取最小值即可

AC CODE

 1 #include <bits/stdc++.h> 
 2 using namespace std;
 3 int n,k,prep[200009],minn;
 4 string a;
 5 
 6 void count(string s){
 7     int p=0;
 8     for(int i=1;i<=n;i++){
 9         prep[i]=prep[i-1];
10         if(a[i]!=s[p])prep[i]++;
11         if(p==2)p=0;
12         else p++;
13     }
14     for(int i=k;i<=n;i++)
15         minn=min(minn,prep[i]-prep[i-k]); 
16 }
17 
18 void solve(){
19     minn=114514;
20     cin>>n>>k>>a;
21     a=' '+a;
22     count("PIG");
23     count("IGP");
24     count("GPI");
25     cout<<minn<<"\n";
26 }
27 
28 int main() {  
29     freopen("A.in","r",stdin);
30     freopen("A.out","w",stdout);
31     prep[0]=0;
32     int T;
33     cin>>T;
34     while(T--)solve();
35     return 0;
36 }

 T2:Seat

 “大胆猜测,小心求证”

观察到两个样例的n都是奇数,由此可以大胆地猜测当n为偶数时无解

那么如何证明呢?

当找不到规律时,我们可以把样例中规模较大而便于计算的样例拿去手算

选择样例2进行手算,过程如下:

很显然,此过程中,是两组两组的编号进行操作的,我们将此定义为一组操作

我们还发现当一个编号被移动到目标位置(即其正对面的位置)以后,不再被操作(处0以外)

因此,每一组操作具有独立性,即每一组操作之间互不影响

那么显而易见,对于每一组操作,假设现在需要交换的两组为(a,a')和(b,b'),坐在空位对面的人为x,则操作顺序[a',a,x,a',b',x,b',a',x,b',b']一定可以交换这两组,然后分组交换最后判断空位的位置是否需要再交换一次即可。

那么很明显,当n为偶数时,总会有一组操作无法组成两组编号加上一个空位(奇偶性),也就意味着无法进行上述操作,故当n为偶数时无解,直接输出"-1"即可

AC CODE

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N = 2e5 + 5;
 4 int n,m,a[N];
 5 int main(){
 6     freopen("B.in","r",stdin);
 7     freopen("B.out","w",stdout);
 8     scanf("%d",&n);
 9     for(int i = 0; i <= 2 * n - 1; i++) scanf("%d",&a[i]);
10     int pos = 0;
11     for(int i = 0; i <= 2 * n - 1; i++){
12         if(a[i] == 0) pos = i;
13     }
14     if(n % 2 == 0){
15         puts("-1");
16         return 0;
17     }
18     printf("%d\n", (n / 2) * 11 + ((n - 1) % 4 == 0));
19     bool flag = 0;
20     for(int i = 0; i <n ; i++){
21         
22         if(a[i] != 0 && a[i + n] != 0){
23             int j = i + 1;
24             if(a[j] == 0 || a[j + n] == 0) j++;
25             if(pos < n){
26                 printf("%d ",a[i + n]);
27                 printf("%d ",a[i]);
28                 printf("%d ",a[(pos + n) % (2 * n)]);
29                 printf("%d ",a[i + n]);
30                 printf("%d ",a[j + n]);
31                 printf("%d ",a[(pos + n) % (2 * n)]);
32                 printf("%d ",a[i + n]);
33                 printf("%d ",a[j + n]);
34                 printf("%d ",a[(pos + n) % (2 * n)]);
35                 printf("%d ",a[j]);
36                 printf("%d ",a[j + n]);
37             }
38             else{
39                 printf("%d ",a[i]);
40                 printf("%d ",a[i + n]);
41                 printf("%d ",a[(pos + n) % (2 * n)]);
42                 printf("%d ",a[i]);
43                 printf("%d ",a[j]);
44                 printf("%d ",a[(pos + n) % (2 * n)]);
45                 printf("%d ",a[i]);
46                 printf("%d ",a[j]);
47                 printf("%d ",a[(pos + n) % (2 * n)]);
48                 printf("%d ",a[j + n]);
49                 printf("%d ",a[j]);
50             }
51             swap(a[pos],a[(pos + n) % (2 * n)]);
52             pos = (pos + n) % (2 * n);
53             i = j;
54             flag^=1;
55         }
56         else continue;
57     }
58     if(!flag) printf("%d ",a[(pos + n) % (2 * n)]);
59     return 0;
60 }

 T3:Travel

 

考虑Dijkstra算法的流程。

如果我们将所有点同时当作起点放入单调队列中,并分别维护从每个点出发的最短路,前k个从队列中弹出的点对即为所求答案。

但是如果对于每个弹出的(s,t)点对,更新其所有边可能导致k的代价。

考虑这样一种情况,假设链接点t按照边权从小到大排序,et(i)为与点t相连的权值第i大的边,在(s,t)+et(i)弹出单调队列前,(s,t)+et(i+1)一定不会成为答案。

故我们对于每个弹出队列的点对(s,t)+et(i),只需更新其相连的权值最小的边与(s,t)+et(i+1)即可

时间复杂度O(N+K)log(N+K)+MlogM)

AC CODE

 1 #pragma GCC optimize ("O3")
 2 #pragma GCC target ("sse4")
 3 #include <bits/stdc++.h>
 4 #include <ext/pb_ds/tree_policy.hpp>
 5 #include <ext/pb_ds/assoc_container.hpp>
 6 using namespace std;
 7 using namespace __gnu_pbds;
 8 typedef long long ll;
 9 typedef long double ld;
10 typedef complex<ld> cd;
11 typedef pair<int, int> pi;
12 typedef pair<ll,ll> pl;
13 typedef pair<ld,ld> pd;
14 typedef vector<int> vi;
15 typedef vector<ld> vd;
16 typedef vector<ll> vl;
17 typedef vector<pi> vpi;
18 typedef vector<pl> vpl;
19 typedef vector<cd> vcd;
20 template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;
21 #define FOR(i, a, b) for (int i=a; i<(b); i++)
22 #define F0R(i, a) for (int i=0; i<(a); i++)
23 #define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
24 #define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)
25 #define sz(x) (int)(x).size()
26 #define mp make_pair
27 #define pb push_back
28 #define f first
29 #define s second
30 #define lb lower_bound
31 #define ub upper_bound
32 #define all(x) x.begin(), x.end()
33 #define shandom_ruffle random_shuffle
34 const int MOD = 1e9+7;
35 const ll INF = 1e18;
36 const int MX = 1e5+1; //check the limits, dummy
37 ll ans = 0;
38 struct data {
39     ll weight; int start, last, index;
40     data(ll w, int S, int L, int I) {weight = w; start = S; last = L; index = I;}
41     bool operator<(data other) const{return weight > other.weight;}
42 };
43 int main() {
44     ios_base::sync_with_stdio(0); cin.tie(0);
45     int N, M, K; cin >> N >> M >> K;
46     vector<vpl> graph(N);
47     F0R(i, M) {
48         ll A, B, C; cin >> A >> B >> C; A--; B--;
49         graph[A].pb(mp(C, B));
50         graph[B].pb(mp(C, A));
51     }
52     F0R(i, N)sort(all(graph[i]));
53     priority_queue<data> pq; 
54     K *= 2;
55     set<pl> visited;
56     F0R(i, N) {pq.push(data(graph[i][0].f, i, i, 0));visited.insert(mp(i, i));}
57     while (!pq.empty()) {
58         data cur = pq.top();
59         pq.pop();
60         int nxt = graph[cur.last][cur.index].s;
61         if (!visited.count(mp(cur.start, graph[cur.last][cur.index].s))) {
62             visited.insert(mp(cur.start, graph[cur.last][cur.index].s));
63             K--;
64             ans += cur.weight;
65             if(K == 0) {cout << ans << endl; return 0;}
66             pq.push(data(cur.weight + graph[nxt][0].f, cur.start, nxt, 0));
67         }
68         if (cur.index + 1 < sz(graph[cur.last])) 
69             pq.push(data(cur.weight - graph[cur.last][cur.index].f + graph[cur.last][cur.index + 1].f, cur.start, cur.last, cur.index + 1));
70     }
71     return 0;
72 }

前面那一大堆纯属装X的,不是吗?(滑稽)

T4:Nobel

 

As the saying goes , easier said than done...

首先意识到碰撞只会在相邻的粒子之间发生,一共三种情况:同时向左,同时向右,相向运动,每种情况的碰撞时间可以O(1)求出。我

们对于所有碰撞情况按照时间排序,只要求出每种碰撞为第一次碰撞的概率即可(也就是前i-1种碰撞全不发生减掉前种碰撞全不发生的概率)

每种粒子和他上一个粒子子互相作用的情况可以用2*2矩阵表示累乘即可得到前i种全不发生的概率,用线段树维护矩阵即可。

AC CODE

 1 #include<bits/stdc++.h>
 2 #define re register
 3 #define inc(i,j,k) for(re int i=j;i<=k;i++)
 4 #define ll long long
 5 #define lc o<<1
 6 #define rc o<<1|1
 7 using namespace std;
 8 const int mod=998244353;
 9 const int N=2e5+5;
10 inline int read(){
11     int x=0,f=1;
12     char ch=getchar();
13     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
14     while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=getchar();
15     return f*x;
16 }
17 int n,x[N],v[N],tot;
18 ll p[N],inv,ans;
19 ll qp(ll x,ll k){
20     ll res=1;
21     while(k){
22         if(k&1) res=res*x%mod;
23         k>>=1,x=x*x%mod;
24     }
25     return res;
26 }
27 struct mat{
28     ll m[2][2];    
29     void clear(){memset(m,0,sizeof(m));}
30 }t[N<<2],a[N];
31 mat operator*(mat a,mat b){
32     mat tmp;tmp.clear();
33     inc(i,0,1)
34         inc(j,0,1)
35             inc(k,0,1) (tmp.m[i][j]+=a.m[i][k]*b.m[k][j]%mod)%=mod;
36     return tmp;
37 }
38 struct opt{
39     int u,v,pu,pv;
40     ll dx,dv;
41     opt(){}
42     opt(int uu,int vv,int p_u,int p_v,int d_x,int d_v){u=uu,v=vv,pu=p_u,pv=p_v,dx=d_x,dv=d_v;}
43 }P[N<<2];
44 bool operator<(opt x,opt y){return x.dx*y.dv<y.dx*x.dv;}
45 void ins(int o,int l,int r,int x){
46     if(l==r){t[o]=a[l];return;}
47     int mid=(l+r)>>1;
48     if(x<=mid) ins(lc,l,mid,x);
49     else ins(rc,mid+1,r,x);
50     t[o]=t[lc]*t[rc];
51 }
52 mat query(int o,int l,int r,int x,int y){
53     if(x<=l&&r<=y) return t[o];
54     int mid=(l+r)>>1;
55     if(x>mid) return query(rc,mid+1,r,x,y);
56     if(y<=mid) return query(lc,l,mid,x,y);
57     return query(lc,l,mid,x,y)*query(rc,mid+1,r,x,y);
58 }
59 int main(){
60     inv=qp(100,mod-2);
61     n=read();
62     inc(i,1,n){
63         x[i]=read(),v[i]=read(),p[i]=read();
64         p[i]=p[i]*inv%mod;p[i]=(1-p[i]+mod)%mod;
65         if(i==1){
66             a[i].m[0][0]=p[i];
67             a[i].m[0][1]=(1-p[i]+mod)%mod;
68             ins(1,1,n,i);
69         }
70         else{
71             a[i].m[0][0]=a[i].m[1][0]=p[i];
72             a[i].m[0][1]=a[i].m[1][1]=(1-p[i]+mod)%mod;
73             ins(1,1,n,i);
74             if(v[i]-v[i-1]>0) P[++tot]=opt(i-1,i,0,0,x[i]-x[i-1],v[i]-v[i-1]);
75             if(v[i-1]-v[i]>0) P[++tot]=opt(i-1,i,1,1,x[i]-x[i-1],v[i-1]-v[i]);
76             if(v[i-1]+v[i]>0) P[++tot]=opt(i-1,i,1,0,x[i]-x[i-1],v[i-1]+v[i]);
77         }
78     }    
79     sort(P+1,P+1+tot);
80     inc(i,1,tot){
81         int l=P[i].u,r=P[i].v;
82         ll ret=P[i].dx*qp(P[i].dv,mod-2)%mod;
83         mat tmp;
84         tmp=query(1,1,n,1,l);
85         ret=ret*(tmp.m[0][P[i].pu]+tmp.m[1][P[i].pu])%mod;
86         ret=ret*a[r].m[P[i].pu][P[i].pv]%mod;
87         if(r!=n){
88             tmp=query(1,1,n,r+1,n);
89             ret=ret*(tmp.m[P[i].pv][0]+tmp.m[P[i].pv][1])%mod;
90         }
91         (ans+=ret)%=mod;
92         a[r].m[P[i].pu][P[i].pv]=0;
93         ins(1,1,n,r);
94     }
95     printf("%lld",ans);
96 }

归(做)纳(题)与(的)总(心)结(得)

T1:半小时就切了好吧O(∩_∩)O

T2:找到规律就好做啦~(ง •_•)ง

T3:亿点点小难哦~(>人<;)

T4:整个人都麻了好吧( ఠൠఠ )ノ

 

终于又水了一篇喽,溜了溜了ε=ε=ε=(~ ̄▽ ̄)~