今天又只过了一题,很差!!!
E题应该能想出来的,构造题多找性质,发现很强的性质后构造就很方面了。
看题要有舍有得,有些题显然很难就没必要看了。把注意力放在有人做的可做题上,静下心来深入思考很重要。
如果没有别的题可做,1道题想一小时很正常。多想别的做法,甚至乱搞,但是肯定不能过的做法别多纠结。胆大尝试做法,但过不了果断放弃,不要浪费太多时间。
大胆利用性质猜结论!
调题应该更快,敢于问。注意细节错误!静下心来用眼读代码,边读边思考,减少对拍,因为考场上没法也没时间对拍!!!
题解:
A:求多项式的商。巧妙推式子。
主要是推式子很巧,很好写!
#include<bits/stdc++.h>
using namespace std;
#define maxn 5020
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
typedef long long ll;
const ll mod = 1e9 + 7;
ll a[maxn],b[maxn],c[maxn],ans,mx;
int m;
inline ll power(ll x,ll y){
ll res = 1;
while ( y ){
if ( y & 1 ) res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return (res + mod) % mod;
}
void cal_C(){
rep(i,1,m){
ll mul = 1,x = 1,cur = 0;
rep(j,1,m) if ( j != i ) mul = mul * (a[j] - a[i]) % mod;
mul = power(mul,mod - 2);
rep(j,0,m - 2) cur = (cur + x * b[j]) % mod , x = x * (-a[i]) % mod;
c[i] = (cur * mul % mod + mod) % mod;
}
//rep(i,1,m) c[i] = (c[i] + c[i - 1]) % mod;
}
void solve(){
rep(i,1,mx){
ll cur = 0;
rep(j,1,m){
if ( a[j] < i ) cur = (cur + c[j]) % mod;
}
ans = (ans + cur * power(i,mod - 2)) % mod;
}
ans = (ans % mod + mod) % mod;
printf("%lld\n",ans);
}
int main(){
freopen("input.txt","r",stdin);
while ( ~scanf("%d",&m) ){
mx = ans = 0;
rep(i,1,m) scanf("%lld",&a[i]) , mx = max(mx,a[i]);
rep(i,0,m - 2) scanf("%lld",&b[i]);
cal_C();
solve();
}
return 0;
}
B:巧妙的贪心,利用每个联通块必选一个点,其余点从小到大选。大胆推性质,想结论!
C:N*N矩阵,每行每列填一个数,使两两连线不同。
用原根构造(g^(1 - n-1)恰好为1- p-1).因为保证n +1为质数,所以大胆猜想与原根有关。
填(i,g^i % (n + 1))
D:求对于每个前缀i,找一个分界点j,xorsum(1,j) + xorsum(j +1,i)最大。
每一位,出现奇数次为0(因为无论怎么选都贡献1),偶数次为1(想选到奇数次分开,就贡献2)
相当于查询x在pre中&的最大值。
F[1<<10][1<<10]的分块过不了
考虑直接对一个pre的所有子集进行更新,查询时只需知道当前要填的数是否被包含,就可以唯一确定,非常巧妙!
O(nlogn)
注意输出优化要特判负数和0
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define maxn (1 << 22)
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define inf 1e8
int a[maxn],ans[maxn],n;
int q[maxn],hh,tt,dfstime,vis[maxn];
inline int read(){
register int num = 0;
register char ch = getchar();
while ( ch > '9' || ch < '0' ) ch = getchar();
while ( ch <= '9' && ch >= '0' ) num = num * 10 + ch - '0' , ch = getchar();
return num;
}
int num[10];
inline void write(int x){
register int cnt = 0;
if ( !x ){ printf("0"); return; }
while ( x ) num[++cnt] = x % 10 , x /= 10;
while ( cnt ) putchar(num[cnt--] + '0');
}
inline void insert(int x){
if ( vis[x] == dfstime ) return;
tt = hh = 0; q[tt++] = x , vis[x] = dfstime;
while ( hh < tt ){
int x = q[hh++];
if ( !x ) continue;
rep(i,0,19){
if ( (x >> i) & 1 ){
if ( vis[x ^ (1 << i)] != dfstime ){
vis[x ^ (1 << i)] = dfstime;
q[tt++] = x ^ (1 << i);
}
}
}
}
}
inline int query(int x){
int cur = 0;
repd(i,19,0){
if ( x & (1 << i) ){
if ( vis[cur | (1 << i)] == dfstime ) cur |= 1 << i;
}
}
return cur;
}
int main(){
freopen("input.txt","r",stdin);
// freopen("1.out","w",stdout);
while ( ~scanf("%d",&n) ){
++dfstime;
int pre = 0,cur = 0,S = (1 << 20) - 1;
rep(i,1,n){
a[i] = read() , pre ^= a[i] , cur = pre ^ S;
insert(pre);
ans[i] = query(cur) * 2 + pre;
}
rep(i,1,n){
write(ans[i]);
// if ( i < n ) putchar(' ');
// else putchar(10);
if ( i < n ) printf(" ");
else printf("\n");
}
}
return 0;
}
E:给出后缀排序后第i位的位置,构造一个0,1的可行解。
每次找到最后一个位置的排名,如果在第一则填0删去,不影响其他点排名。如果不在第一位则必须填1。并且它之前全部为0,之后全部为1。再一次后缀数组判断是否可行。
注意后缀数组有些地方要倒着for(位置靠后字典序更小)
还要一种很巧的判定方法。
rk[sa[i] +1] > rk[sa[i +1] +1]则所需字符集+1,使用于字符集更大的情况
#include<bits/stdc++.h>
using namespace std;
#define maxn 100020
#define rep(i,l,r) for (register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
int a[maxn];
int s[maxn],c[maxn],t1[maxn * 2],t2[maxn * 2],sa[maxn];
int n;
//sa[i]表示排名为i的后缀的位置
//rk[i]表示第i个后缀的排名
//x[i]表示i的排名(第一关键字)
//y[i]表示第二关键字排名为i的后缀的起始位置
//h[i]表示后缀i在排序后与前一位的lcp
//求i,j的lcp是排序后rk[i],rk[j],height的min
void suffix_array(){
int m = 1 , *x = t1 , *y = t2;
rep(i,0,m) c[i] = 0;
rep(i,0,n - 1) c[x[i] = s[i]]++;
rep(i,1,m) c[i] += c[i - 1];
rep(i,0,n - 1) sa[--c[x[i]]] = i;
// rep(i,1,n) cout<<sa[i - 1]<<" ";
// cout<<endl;;
for (register int k = 1 ; k < n ; k <<= 1){
register int p = 0;
memset(y,0,sizeof(t1));
repd(i,n - 1,n - k) y[p++] = i; //必须倒着for,在后面的位置更小
rep(i,0,n - 1) if ( sa[i] >= k ) y[p++] = sa[i] - k;
rep(i,0,m) c[i] = 0;
rep(i,0,n - 1) c[x[y[i]]]++;
rep(i,1,m) c[i] += c[i - 1];
repd(i,n - 1,0) sa[--c[x[y[i]]]] = y[i];
p = 0 , swap(x,y) , x[sa[0]] = ++p;
rep(i,1,n - 1) x[sa[i]] = (y[sa[i]] == y[sa[i - 1]]) && (y[sa[i] + k] == y[sa[i - 1] + k]) ? p : ++p;
if ( p >= n ) break; //如果当前已经完成排名,则break
m = p;
}
}
bool check(){
// rep(i,1,n) cout<<sa[i - 1]<<" ";
// cout<<endl;;
rep(i,1,n) if ( a[i] != sa[i - 1] + 1 ) return 0;
return 1;
}
int main(){
freopen("input.txt","r",stdin);
while ( ~scanf("%d",&n) ){
rep(i,1,n) scanf("%d",&a[i]);
int id = 1;
while ( a[id] == n - id + 1 ) id++;
if ( id >= n ){ printf("YES\n"); continue; }
rep(i,id,n) if ( a[i] == n - id + 1){ id = i; break; }
rep(i,1,id - 1) s[a[i] - 1] = 0;
rep(i,id,n) s[a[i] - 1] = 1;
suffix_array();
if ( check() ) printf("YES\n");
else printf("NO\n");
}
return 0;
}
F:特技分块,好题
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define maxn 200020
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define inf 1e8
typedef long long ll;
inline int read(){
register int num = 0;
register char ch = getchar();
while ( ch > '9' || ch < '0' ) ch = getchar();
while ( ch <= '9' && ch >= '0' ) num = num * 10 + ch - '0' , ch = getchar();
return num;
}
int num[10];
inline void write(int x){
register int cnt = 0;
if ( !x ){ printf("0"); return; } //Ò»¶šÒªÌØÅÐ0£¡£¡£¡
while ( x ) num[++cnt] = x % 10 , x /= 10;
while ( cnt ) putchar(num[cnt--] + '0');
}
struct node{
int x,y;
}dt[maxn];
int n,m,q,deg[maxn],sz,tag[maxn],id[maxn],tot,exi[maxn];
ll v[maxn],w[2][1020][1020];
int big[maxn],rev[maxn];
vector <int> vec[maxn];
void init(){
rep(i,1,n) tag[i] = deg[i] = id[i] = 0 , vec[i].clear();
rep(i,1,n) v[i] = (ll)rand() * rand() * rand();
rep(i,0,m / sz) rev[i] = 0;
rep(i,0,m) exi[i] = 1;
memset(w,0,sizeof(w));
tot = 0;
}
inline void update(int i,int cur){
int x = dt[i].x , y = dt[i].y;
if ( tag[x] ){
w[0][cur][id[x]] ^= v[y];
w[1][cur][id[x]] ^= v[y];
}
if ( tag[y] ){
w[0][cur][id[y]] ^= v[x];
w[1][cur][id[y]] ^= v[x];
}
}
inline void modify(int l,int r){
int L = l == 0 ? 0 : ((l - 1) / sz + 1),R = (r + 1) / sz - 1;
rep(i,L,R){
rev[i] ^= 1;
}
if ( R >= L ){
rep(i,l,sz * L - 1) exi[i] ^= 1 , update(i,i / sz);
rep(i,(R + 1) * sz,r) exi[i] ^= 1 , update(i,i / sz);
}
else{
//ÖЌ䲻°üº¬ÈÎÒâÒ»¿éÒªÌØÅÐ
rep(i,l,r) exi[i] ^= 1 , update(i,i / sz);
}
}
inline ll cal(int id,int x){
if ( exi[id] ^ rev[id / sz] ){
if ( dt[id].x == x ) return v[dt[id].y];
return v[dt[id].x];
}
return 0;
}
ll query(int x){
ll res = 0;
if ( tag[x] ){
rep(i,0,m / sz){
res ^= w[rev[i]][i][id[x]];
}
}
else{
for (register int i = 0 ; i < vec[x].size() ; i++){
res ^= cal(vec[x][i],x);
}
}
return res;
}
int main(){
freopen("input.txt","r",stdin);
while ( ~scanf("%d %d",&n,&m) ){
sz = sqrt(m * 2);
init();
rep(i,0,m - 1){
dt[i].x = read() , dt[i].y = read();
deg[dt[i].x]++ , deg[dt[i].y]++;
vec[dt[i].x].push_back((int)i) , vec[dt[i].y].push_back((int)i);
}
rep(i,1,n) if ( deg[i] > sz ) tag[i] = 1 , big[++tot] = i , id[i] = tot;;
rep(i,0,m / sz){
rep(j,i * sz,min(m - 1,(i + 1) * sz - 1)){
int x = dt[i].x,y = dt[i].y;
if ( tag[x] ) w[0][i][id[x]] ^= v[y];
if ( tag[y] ) w[0][i][id[y]] ^= v[x];
}
}
q = read();
while ( q-- ){
int tp,x,y;
tp = read() , x = read() , y = read();
if ( tp == 1 ){
modify(x - 1,y - 1);
}
else{
if ( query(x) == query(y) ) printf("1");
else printf("0");
}
}
printf("\n");
}
return 0;
}
G:NTT优化数位DP
#include<bits/stdc++.h>
using namespace std;
#define maxn 100020
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define inf 1e8
inline int read(){
register int num = 0;
register char ch = getchar();
while ( ch > '9' || ch < '0' ) ch = getchar();
while ( ch <= '9' && ch >= '0' ) num = num * 10 + ch - '0' , ch = getchar();
return num;
}
int num[10];
inline void write(int x){
register int cnt = 0;
if ( !x ){ printf("0"); return; } //Ò»¶šÒªÌØÅÐ0£¡£¡£¡
while ( x ) num[++cnt] = x % 10 , x /= 10;
while ( cnt ) putchar(num[cnt--] + '0');
}
typedef long long ll;
const ll p = 998244353,g = 3;
const int len = 32768,cnt = 15,mod = 10857;
ll f[32][maxn],c[maxn],res[maxn],inv;
int n,rev[maxn];
int a[6] = {2,3,5,7,11,47},t[5] = {1,2,3,5,7};
inline ll power(ll x,ll y,ll p){
ll res = 1;
while ( y ){
if ( y & 1 ) res = res * x % p;
x = x * x % p;
y >>= 1;
}
return res;
}
void NTT(ll a[],int tag){
rep(i,0,len - 1) if ( rev[i] > i ) swap(a[rev[i]],a[i]);
for (register int i = 1 ; i < len ; i <<= 1){
ll wn = power(g,(p - 1) / (i << 1),p);
for (register int j = 0 ; j < len ; j += (i << 1)){
ll w = 1;
for (register int k = 0 ; k < i ; k++){
ll x = a[j + k] , y = a[i + j + k] * w % p;
a[j + k] = (x + y) % p;
a[i + j + k] = (x - y + p) % p;
w = w * wn % p;
}
}
}
if ( tag == -1 ){
reverse(a + 1,a + len);
rep(i,0,len - 1) a[i] = inv * a[i] % p;
}
}
void qpow(ll a[],ll b[],ll n){
rep(i,0,len - 1) c[i] = 0;
rep(i,0,len - 1) c[n * i % mod] = (c[n * i % mod] + a[i]) % p;
NTT(c,1);
rep(i,0,len - 1) c[i] = c[i] * b[i] % p;
NTT(c,-1);
rep(i,0,len - 1) a[i] = 0;
rep(i,0,len - 1) a[i % mod] = (a[i % mod] + c[i]) % p;
}
void init(){
inv = power(len,p - 2,p);
rep(i,0,len - 1){
int cur = 0;
rep(j,0,cnt - 1){
if ( i & (1 << j) ) cur += 1 << (cnt - j - 1);
}
rev[i] = cur;
}
rep(i,0,4) f[0][t[i]] = 1;
rep(i,1,29){
memcpy(f[i],f[i - 1],sizeof(f[i])) , NTT(f[i - 1],1);
qpow(f[i],f[i - 1],power(10,1 << (i - 1),mod));
}
NTT(f[29],1);
}
int check(int x){
rep(i,0,5) if ( (x % a[i]) == 0 ) return 0;
return 1;
}
int main(){
// freopen("input.txt","r",stdin);
init();
while ( ~scanf("%d",&n) ){
n--;
memset(res,0,sizeof(res));
res[0] = 1;
repd(i,29,0){
if ( n & (1 << i) ) qpow(res,f[i],power(10,1 << i,mod));
}
ll ans = 0;
// rep(i,0,10) cout<<res[i]<<" ";
// cout<<endl;
rep(i,0,mod - 1){
int cnt = 0;
rep(j,0,4) if ( check(i * 10 + t[j]) ) cnt++;
ans = (ans + res[i] * cnt) % p;
}
printf("%lld\n",ans);
}
return 0;
}
H:用圆的包含关系建树,然后DP,明天写
明天目标过3题,进入前5名!提高思维速度,减少代码错误和罚时,静心深入思考!!!
明天早点睡!一刻不能放松!先调完题才能回寝室!