7.28 2020 Multi-University Training Contest 3題解及補題
目錄
7.28 2020 Multi-University Training Contest 3題解及補題
比賽過程
這場的1004一開始理解題意,不知道往哪個方向想,確定知識點不太準確。1009括號匹配的知識點,一開始考慮欠周全。
題解
1004 Tokitsukaze and Multiple
題意
給定兩個數n和p,接下來是長度為n的序列。每次可以把序列相鄰的兩個數合併為兩個數的和,陣列的長度減1。求陣列中是p的倍數的數最多有多少個。
解法
首先,如果單獨的一個a[i]%p0,ans++,然後考慮剩下的數怎麼組合。可以開一個set,如果a[i]%p0,ans++,set.clear()。如果a[i]%p!=0,記錄兩個值,分別是a[i]+a[i+1]……的和sum,然後把sum%p分別放入set裡面,每次新的a[i]都檢查sum%p的值是不是在set裡面,如果在set裡面,清空set,ans++
程式碼
#include<bits/stdc++.h> #define ll long long using namespace std; int main() { int t; scanf("%d",&t); while(t--){ ll n,p; scanf("%lld%lld",&n,&p); ll a[n+1]; ll ans=0; for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); } set<int> st; ll sum=0; for(int i=1;i<=n;i++){ if(a[i]%p==0){ ans++; st.clear(); sum=0; continue; } sum+=a[i]; if(sum%p==0||(st.count(sum%p))){ ans++; sum=0; st.clear(); continue; } else{ st.insert(sum%p); } } cout<<ans<<endl; } }
1005 Little W and Contest
題意
給n個人與每個的能力值(2或1),組一個3人的隊能力和至少5以上,同在一個集合的人不能組隊,最開始每個人都在自己的集合,詢問n-1次,每次將任意兩人所在的集合合併之後輸出多少種組隊方案。
解法
構造一個二元多項式。
藉助 x 表示人數,藉助 y 表示戰鬥力。
則多項式中的項 \(kx^ay^b\) 表示:組成由 a 人組成戰鬥力為 b 的團隊,方案總數為 k。
對於一個有 n 人戰鬥力為 1,m 人戰鬥力為 2 的連通塊,則可以用多項式 \((nxy + mxy^2 + 1)\) 來表
示。新增連通塊只要多項式乘進去,要刪除連通塊消除貢獻只要多項式除回來即可。
由於冪較小,藉助二維揹包來做多項式乘除法即可。
正貢獻 01 揹包為多項式乘法,負貢獻完全揹包為多項式除法
程式碼
#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
using namespace std;
const long long mod=1e9+7;
const int MAXN=100005;
struct Generating_function
{
long long ki[4][7];//x y
Generating_function()
{
memset(ki,0,sizeof(ki));
ki[0][0]=1;
}
void init()
{
memset(ki,0,sizeof(ki));
ki[0][0]=1;
}
void mult(long long a,long long b)
{
for(int i=3;i;--i)
{
for(int j=6;j;--j)
{
ki[i][j]+=a*ki[i-1][j-1]%mod;
if(j>1)ki[i][j]+=b*ki[i-1][j-2]%mod;
ki[i][j]%=mod;
}
}
}
void div(long long a,long long b)
{
for(int i=1;i<=3;++i)
{
for(int j=1;j<=6;++j)
{
ki[i][j]-=a*ki[i-1][j-1]%mod;
if(j>1)ki[i][j]-=b*ki[i-1][j-2]%mod;
ki[i][j]=(ki[i][j]%mod+mod)%mod;
}
}
}
long long get()
{
return (ki[3][5]+ki[3][6])%mod;
}
}solve;
int fa[MAXN],a[MAXN],b[MAXN],x,n,u,v;
int findf(int x)
{
return fa[x]==x?x:fa[x]=findf(fa[x]);
}
void unions(int x,int y)
{
a[findf(y)]+=a[findf(x)];
b[findf(y)]+=b[findf(x)];
fa[findf(x)]=findf(y);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
solve.init();
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d",&x);
fa[i]=i;
a[i]=b[i]=0;
if(x==1)++a[i];
else ++b[i];
solve.mult(a[i],b[i]);
}
printf("%lld\n",solve.get());
for(int i=1;i<n;++i)
{
scanf("%d %d",&u,&v);
solve.div(a[findf(u)],b[findf(u)]);
solve.div(a[findf(v)],b[findf(v)]);
unions(u,v);
solve.mult(a[findf(u)],b[findf(u)]);
printf("%lld\n",solve.get());
}
}
return 0;
}
1006 X Number
題意
解法
程式碼
//將內容替換成程式碼
1007 Tokitsukaze and Rescue
題意
解法
程式碼
//將內容替換成程式碼
1008 Triangle Collision
題意
有一小球在一個邊長為LL的等邊三角形內運動
其擁有一個初始位置\((x,y)\)以及恆定速度\((V_x,V_y)\)
詢問當第k次撞擊三角形邊緣時花費的時間
保證小球在前k次撞擊不會撞到三角形的某個角
解法
主要在於旋轉,因為看的大佬的部落格,圖片不會製作,這裡放個圖片連結
需要用到平面幾何的知識,注意知識點儲存
程式碼
#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
using namespace std;
typedef long long ll;
const double eps=1e-12;
const double PI=acos(-1.0);
int dbcmp(double x){
if(fabs(x)<eps)
return 0;
return x<0?-1:1;
}
struct Point{
double x,y;
Point(){}
Point(double _x,double _y){
x=_x;
y=_y;
}
bool operator == (Point b)const{
return dbcmp(x-b.x)==0&&dbcmp(y-b.y)==0;
}
Point operator -(const Point &b)const{ //叉積
return Point(x-b.x,y-b.y);
}
double operator ^(const Point &b)const{ //點積
return x*b.y-y*b.x;
}
double operator *(const Point &b)const{
return x*b.x+y*b.y;
}
Point operator +(const Point &b)const{
return Point(x+b.x,y+b.y);
}
Point operator *(const double &k)const{
return Point(x*k,y*k);
}
Point operator /(const double &k)const{
return Point(x/k,y/k);
}
double distance(Point p){
return hypot(x-p.x,y-p.y);
}
Point Rotate(double rad){ //逆時針旋轉
return Point(x*cos(rad)-y*sin(rad),x*sin(rad)+y*cos(rad));
}
};
struct Line{
Point s,e;
Line(){}
Line(Point _s,Point _e){
s=_s;
e=_e;
}
bool pointonseg(Point p){
return dbcmp((p-s)^(e-s))==0&&dbcmp((p-s)*(p-e))<=0;
}
double getDistance(Point A){ //點到直線的距離
return fabs((A-s)^(A-e)/s.distance(e));
}
Point crosspoint(Line v){
double a1=(v.e-v.s)^(s-v.s);
double a2=(v.e-v.s)^(e-v.s);
return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
}
};
const double sq3=sqrt(3);
double L,x,y,vx,vy,h;
int k;
Point A,B,C,oripot,v1,v2,v3;
Line AB,AC,BC;
bool check(double tim)
{
ll kk=0;
double dis;
dis=BC.getDistance(oripot)+v1.y*tim; //第一種座標系對應邊BC,計算出起點高度+y軸經過距離Δy
if(dis<0)
kk+=(ll)((-dis)/h)+1; //如果方向為負方向,計算結果與直接整除略有不同
else
kk+=(ll)(dis/h); //正方向正常整除
dis=AC.getDistance(oripot)+v2.y*tim; //第一種座標系對應邊AC,計算出起點高度+y軸經過距離Δy
if(dis<0)
kk+=(ll)((-dis)/h)+1;
else
kk+=(ll)(dis/h);
dis=AB.getDistance(oripot)+v3.y*tim; //第一種座標系對應邊AB,計算出起點高度+y軸經過距離Δy
if(dis<0)
kk+=(ll)((-dis)/h)+1;
else
kk+=(ll)(dis/h);
return kk>=k; //最後判斷當前的交點個數是否大於等於要求的個數
}
void solve()
{
cin>>L>>x>>y>>vx>>vy>>k;
h=sq3*L/2.0; //三角形高度
v1=Point(vx,vy); //第一種座標系下的速度向量
v2=v1.Rotate(PI*2.0/3); //第二種座標系下的速度向量(逆時針旋轉120°)
v3=v1.Rotate(-PI*2.0/3); //第三種座標系下的速度向量(順時針旋轉120°)
oripot=Point(x,y); //小球初始位置
A=Point(0,h); //三角形上角
B=Point(L/2.0,0); //三角形右角
C=Point(-L/2.0,0); //三角形左角
AB=Line(A,B); //三條邊組成的線
AC=Line(A,C);
BC=Line(B,C);
double l=0,r=1e10,mid; //二分時間,計算交點個數是否符合條件
while(r-l>=1e-5) //題目不卡精度,實測1e-4也能過
{
mid=(l+r)/2.0;
if(check(mid))
r=mid;
else
l=mid;
}
cout<<r<<'\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cout<<fixed<<setprecision(8);
int T;cin>>T;
for(int t=1;t<=T;t++)
solve();
return 0;
}
1009 Parentheses Matching
題意
給定一個括號序列,其中僅包含()*
,任務就是替換其中的*
為()
或者空字串,是的原字串平衡且字典序最小。
解法
括號匹配,注意多個方面的思考,先將正常的括號入棧,如果左括號少,那就將最前面的星號邊成左括號,如果最後還有多餘的左括號,那就將最後面的星號變成右括號
程式碼
#include <bits/stdc++.h>
#define IO ios::sync_with_stdio(0), cin.tie(0)
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const int inf = ~0u >> 1;
typedef pair<int, int> P;
#define REP(i, a, n) for (int i = a; i < (n); ++i)
#define PER(i, a, n) for (int i = (n)-1; i >= a; --i)
char p[maxn];
int ans[maxn];
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%s", p);
int n = strlen(p);
//cout << "p =" << p << endl;
int sum = 0;
stack<int> s;
bool flag = true;
queue<int> xh;
REP(i, 0, n) {
ans[i] = 0;
if (p[i] == '(') {
s.push(i);
} else if (p[i] == ')') {
//cout << s.size() << endl;
if (!s.empty()) {
ans[s.top()] = 1;
//cout << "top = " << s.top().second << endl;
ans[i] = 2;
s.pop();
} else {
if (i > 0 && sum > 0) {
ans[i] = 2;
ans[xh.front()] = 1;
sum--;
xh.pop();
} else {
flag = false;
break;
}
}
} else {
xh.push(i);
sum++;
}
}
if (!flag) {
printf("No solution!\n");
continue;
}
int sum2 = 0;
queue<int> xh2;
PER(i, 0, n) {
if (p[i] == '*') {
sum2++;
xh2.push(i);
}
//cout << "i = " << i << " p = " << p << " ans = " << ans <<endl;
if (p[i] == '(' && ans[i] == 0) {
if (sum2 > 0) {
ans[xh2.front()] = 2;
ans[i] = 1;
xh2.pop();
sum2--;
} else {
flag = false;
break;
}
}
}
if (!flag) {
printf("No solution!\n");
continue;
}
REP(i, 0, n) {
if (ans[i] == 1) {
printf("(");
} else if (ans[i] == 2) {
printf(")");
} else if (ans[i] == 0){
printf("");
}
}
printf("\n");
}
return 0;
}