A
签到
B
给你一串有括号组成的字符串,要求你每次删去一个简单括号序列,要求你用最少的次数把字符串里的括号删完(简单括号序列:前n个为‘(’,后n个为’)‘);
思路:直接贪心字符串里的第一个括号(匹配字符串里的最后一个括号),这样匹配第一次肯定是删掉最长的,同时他删一次后就找不到其他的了
#include <bits/stdc++.h>
using namespace std;
const int maxn=4e5+10;
typedef long long ll;
int n,m,T,sum,piuy;
int cnt,resss,cntt;
string SSSS,ss;
int ans[maxn],b[maxn],kk[maxn],laa[maxn],poo[maxn];
bool kop(int a,int b){
return a>b;
}
int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
return x*f;
}
void ini()
{
int pp=0;
int ppp=0;
for(int i=1;i<=10;i++)pp++;
for(int i=10;i<=15;i++) ppp++;
}
void run()
{
for(int i=0;i<SSSS.size();i++) {
if(SSSS[i]==')') poo[++cnt]=i+1;
else laa[++resss]=i+1;
}
sort(poo+1,poo+1+cnt,kop);
sort(laa+1,laa+1+resss);
int i=1,j=1;
while(1){
if(j>resss||cnt<i) break;
if(laa[i]<poo[j]) {
kk[++cntt]=laa[i];
kk[++cntt]=poo[j];
i++,j++;
piuy=piuy+2;
}
else break;
}
if(piuy==0)
puts("0");
else{
puts("1");
cout<<piuy<<endl;
sort(kk+1,kk+1+cntt);
for(int i=1;i<=cntt;i++) cout<<kk[i]<<" ";
puts("");
}
}
int main()
{
ini();
cin>>SSSS;
run();
}
C
由抽屉原理可知,当n>mn>m时,必定存在两个aiai模mm同余,此时答案为00
否则可以直接On2暴力
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+11;
typedef long long ll;
int cnt,resss,cntt;
string SSSS,ss;
int ans[maxn],b[maxn],kk[maxn],laa[maxn],poo[maxn];
ll a[maxn],mod,n;
int mpp[maxn];
bool kop(int a,int b){
return a>b;
}
ll read(){
char c=getchar();ll x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
return x*f;
}
void ini()
{
int pp=0;
int ppp=0;
for(int i=1;i<=10;i++)pp++;
for(int i=10;i<=15;i++) ppp++;
}
int run()
{
n=read(),mod=read();
// rep(i,1,n) a[i]=i;//scanf("%lld",&a[i]);
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++){
if(mpp[a[i]%mod]){
puts("0");
return 0;
}
++mpp[a[i]%mod];
}
ll ress=1;
for(int i=1;i<=n;++i){
for(int j=1+i;j<=n;j++){
ress=ress*(a[i]-a[j])%mod;
}
}
if(ress<=-1) ress=-ress;
cout<<ress<<endl;
}
int main()
{
ini();
run();
}
D
给你一棵树,求出他的根,你可以询问u,v的lca最多n/2次
可以发现一棵树度数为1的点至少会有一个,因此可以每次挑出两个度数为1的点x,yx,y进行询问,若结果等于其中一个点,则其必定为根。否则删除这两个点并把新出现的度数为1的点加入集合,最坏情况就是恰好询问⌊n2⌋⌊n2⌋次
#include <bits/stdc++.h>
using namespace std;
#define TLE std::ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define ll long long
#define pb push_back
typedef pair<int,int> pii;
const ll mod = 1000000000 ;
const int INF=0x3f3f3f3f;
using namespace std;
const int mxn = 3e5+7 ;
int n,t,m,k,l,r,res,prime[mxn],isprime[mxn],phi[mxn],dis[mxn],head[mxn];
string str;
vector<int>ans[mxn];
queue<int>q;
int cnt[mxn];
bool vis[mxn];
void del(int x)
{
for(auto i : ans[x])
{
cnt[i]--;
if(cnt[i]==1) q.push(i);
}
}
int main()
{
TLE;
scanf("%d",&n);
for(int i=1,u,v;i<n;i++)
{
scanf("%d %d",&u,&v);
ans[u].pb(v);ans[v].pb(u);
cnt[u]++;cnt[v]++;
}
for(int i=1;i<=n;i++)
if(cnt[i]==1) q.push(i);
while(q.size()>=2)
{
int u = q.front() ;q.pop();
int v = q.front() ;q.pop();
vis[u] = vis[v] = 1 ;
printf("? %d %d
",u,v);
fflush(stdout);
cin>>k;
if(k==u || k==v ) {printf("! %d
",k); return 0;}
del(u);del(v);
}
k=0;
for(int i=1;i<=n;i++)
if(!vis[i])
printf("! %d
",i) , k++;
// assert(k==1);
return 0 ;
}
E
构造的话直接贪心构造。
先123456...,最后补差就行。
因为从3开始贡献依次为1,1,2,2,3,3,4,4,
当最后一个的贡献大于我们需要的,也就是我们必须弄出恰好m种,而你继续加的话贡献又会大于m,不加又小于
我们发现对这个元素x加1,他的贡献就会减一,所以不段++直到满足,后面的直接从1e9补回来
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '
'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 5000 + 5;
int n, m;
void run() {
cin >> n >> m;
if(n == 1) {
if(m == 0) cout << 1 << '
';
else cout << -1 << '
';
return;
}
vector <int> a;
a.push_back(1);
a.push_back(2);
int now = 1, cnt = 0;
int t = 0, p = 3;
while(t < m) {
if(t + now > m) {
int r = m - t;
--p;
for(int i = p + 1;; i++) {
int L = i - p, R = p;
if((R - L + 1) / 2 == r) {
a.push_back(i);
t += r;
break;
}
}
} else {
a.push_back(p++);
t += now;
if(++cnt == 2) {
++now, cnt = 0;
}
}
}
if(sz(a) > n) {
cout << -1 << '
';
return;
}
int s = 1e9;
while(sz(a) < n) {
a.push_back(s);
s -= 50000;
}
sort(all(a));
for(auto it : a) cout << it << ' ';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}
F
你有n个数, 你可以进行让某个数加一或减一的操作, 求最少的操作次数让这些数最大公因数不为1
思路,我们先假设gcd最少为2时候,那么最多操作只有n次对吧,因为gcd=2说明全是偶数,序列全是奇数我们只需每个位置操作1次,总共就n次。
在最多操作只有n次的条件下,那么一个位置操作数>=2的数量就是<=n/2,反过来说一个位置操作数小于等于1的位置个数就是大于等于n/2,那么也就是我们随机选择一个位置他操作个数小于等于1的几率起码是1/2,那么随机抽取20次,抽到操作个数大于等于2的就得是1/(2^20),忽略不计,所以枚举20次必定找到一个操作数小于等于1的
,那么找到这个数字后对他操作就是三个,-1,0,+1,三种情况分别判断一下,看哪个操作是最好次数就行
然后就行对这个数字的质因数进行判断看哪个质因数是最优的,因为所有数字的gcd,就是他们公共质因数
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
#define ll long long
using namespace std;
template <typename T>
void read(T &x) {
x = 0; bool f = 0;
char c = getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
for (;isdigit(c);c=getchar()) x=x*10+(c^48);
if (f) x=-x;
}
template <typename T>
void write(T x) {
if (x < 0) putchar('-'), x = -x;
if (x >= 10) write(x / 10);
putchar('0' + x % 10);
}
const int N = 205000;
ll a[N], ans, n;
map<ll, int> mp;
void check(ll k) {
ll res = 0; if (mp[k]) return; mp[k] = 1;
for (int i = 1;i <= n; i++) {
if (a[i] >= k) res += min(a[i] % k, k - a[i] % k);
else res += k - a[i];
if (res >= ans) return;
}
ans = min(ans, res);
}
void work(ll x) {
for (ll i = 2;i * i <= x; i++) {
if (x % i) continue;
while (x % i == 0) x /= i;
check(i);
}
if (x > 1) check(x);
}
#include <cstdlib>
#include <ctime>
int main() {
// freopen ("hs.in","r",stdin);
// srand(time(0));
read(n); ans = n;
for (int i = 1;i <= n; i++) read(a[i]);
random_shuffle(a + 1, a + n + 1);
int lim = min(n, 300ll);
for (int i = 1;i <= lim; i++) {
ll x = a[i];
work(x), work(x + 1); if (x > 1) work(x - 1);
}
cout << ans << endl;
return 0;
}